This is an R Markdown Notebook for analysis using data on the DC Bus System (WMATA Metrobus). The data were obtained here:

https://planitmetro.com/2016/11/16/data-download-metrobus-vehicle-location-data/

Control + Alt + Shift + m = rename in scope

Load the packages to be used.

Get the data.

First let’s check the working directory.

getwd()
[1] "/Users/mdturse/Desktop/Analytics/DCMetroBus"

Then, actually get the data.

The working directory was changed to /Users/mdturse/Desktop/Analytics/DCMetroBus/Bus AVL Oct 2016 inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the the working directory for notebook chunks.

Put the daily data together.

AllDays <- bind_rows(list(Oct03Raw, Oct04Raw, Oct05Raw, Oct06Raw, Oct07Raw),
                     .id = c("group")
                    )
Unequal factor levels: coercing to characterUnequal factor levels: coercing to characterUnequal factor levels: coercing to characterUnequal factor levels: coercing to characterUnequal factor levels: coercing to characterUnequal factor levels: coercing to character
# dim(AllDays)
str(AllDays)
'data.frame':   3119443 obs. of  18 variables:
 $ group            : chr  "1" "1" "1" "1" ...
 $ Bus_ID           : int  11 11 11 11 11 11 11 11 11 11 ...
 $ Route            : chr  "S80" "S80" "S80" "S80" ...
 $ RouteAlt         : Factor w/ 14 levels "1","10","11",..: 1 1 1 1 1 1 1 1 6 6 ...
 $ Route_Direction  : chr  "LOOP" "LOOP" "LOOP" "LOOP" ...
 $ Stop_Sequence    : int  7 7 6 3 2 8 1 1 2 3 ...
 $ Stop_ID          : chr  "5004572" "5004572" "5004573" "5002210" ...
 $ Stop_Desc        : chr  "BEULAH ST + CHARLES ARRINGTON DR" "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" ...
 $ Event_Type       : int  4 5 4 4 4 3 3 4 4 4 ...
 $ Event_Description: Factor w/ 3 levels "Serviced Stop                                     ",..: 3 2 3 3 3 1 1 3 3 3 ...
 $ Event_Time       : chr  "10-3-16 6:06:47 AM" "10-3-16 6:07:50 AM" "10-3-16 6:09:47 AM" "10-3-16 6:10:24 AM" ...
 $ Departure_Time   : chr  "10-3-16 6:06:47 AM" "10-3-16 6:08:01 AM" "10-3-16 6:09:47 AM" "10-3-16 6:10:24 AM" ...
 $ Dwell_Time       : int  0 11 0 0 0 0 104 0 0 0 ...
 $ Delta_Time       : int  -177 -27 24 165 25 73 719 0 74 76 ...
 $ Odometer_Distance: int  43543 43543 45139 46418 50115 51074 51303 53836 55633 56163 ...
 $ Latitude         : num  38.8 38.8 38.8 38.8 38.8 ...
 $ Longitude        : num  -77.2 -77.2 -77.2 -77.2 -77.2 ...
 $ Heading          : int  199 253 97 276 15 119 100 89 274 104 ...

Deleting old data frames.

for (i in 3:7){
  rm(list = ls(pattern = paste0("Oct0", i, "Raw")
              )
    )
  
  message("Deleting Oct0", i, "Raw")
  }
Deleting Oct03Raw
Deleting Oct04Raw
Deleting Oct05Raw
Deleting Oct06Raw
Deleting Oct07Raw

Updating variable types.

Then, sorting the data and adding a RowNumber (to be used for identifying rows later in the analyses.)

AllDays$group <- factor(AllDays$group)

Inspecting the values of Stop_ID, and finding that it can take the values “” (blank) and “NULL”.

View(group_by(AllDays_Sorted,
              Stop_ID
             ) %>% 
       summarise(
         Cnt = n()
         ) %>% 
       arrange(Stop_ID)
    )
View(filter(AllDays_Sorted,
            is.na(Stop_ID) |
              Stop_ID == "" |
              Stop_ID == "NULL"
           ) %>% 
       arrange(Stop_Desc)
    )

Creating a table of distinct Stop_Desc values when Stop_ID is “” (blank) or “NULL”.

StopID_New <- filter(AllDays_Sorted,
                     is.na(Stop_ID) |
                       Stop_ID == "" |
                       Stop_ID == "NULL"
                    ) %>% 
  select(Stop_ID, Stop_Desc) %>% 
  distinct() %>% 
  arrange(Stop_ID, Stop_Desc) %>% 
  mutate(StopID_New = 1:nrow(.)
        )
View(StopID_New)

Creating a full updated table by filling in StopID_New for when Stop_ID is “” (blank) or NULL.

AllDays_StopIDNew <- left_join(AllDays_Sorted,
                               select(StopID_New,
                                      Stop_Desc,
                                      StopID_New
                                     ),
                               by = c("Stop_Desc" = "Stop_Desc")
                              ) %>% 
  mutate(StopID_Clean = ifelse(is.na(StopID_New),
                               Stop_ID,
                               StopID_New
                              ),
         StopID_Indicator = factor(ifelse(is.na(StopID_New),
                                          "ID_OK",
                                          "ID_Bad"
                                         )
                                  )
        )
rm(StopID_New)
rm(AllDays_Sorted)
str(AllDays_StopIDNew)
'data.frame':   3119443 obs. of  22 variables:
 $ group            : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Bus_ID           : int  11 11 11 11 11 11 11 11 11 11 ...
 $ Route            : chr  "S80" "S80" "S80" "S80" ...
 $ RouteAlt         : Factor w/ 14 levels "1","10","11",..: 1 1 1 1 1 1 1 1 6 6 ...
 $ Route_Direction  : Factor w/ 12 levels "","ANTICLKW",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ Stop_Sequence    : int  7 7 6 3 2 8 1 1 2 3 ...
 $ Stop_ID          : chr  "5004572" "5004572" "5004573" "5002210" ...
 $ Stop_Desc        : chr  "BEULAH ST + CHARLES ARRINGTON DR" "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" ...
 $ Event_Type       : int  4 5 4 4 4 3 3 4 4 4 ...
 $ Event_Description: Factor w/ 3 levels "Serviced Stop                                     ",..: 3 2 3 3 3 1 1 3 3 3 ...
 $ Event_Time       : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:07:50" ...
 $ Departure_Time   : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:08:01" ...
 $ Dwell_Time       : int  0 11 0 0 0 0 104 0 0 0 ...
 $ Delta_Time       : int  -177 -27 24 165 25 73 719 0 74 76 ...
 $ Odometer_Distance: int  43543 43543 45139 46418 50115 51074 51303 53836 55633 56163 ...
 $ Latitude         : num  38.8 38.8 38.8 38.8 38.8 ...
 $ Longitude        : num  -77.2 -77.2 -77.2 -77.2 -77.2 ...
 $ Heading          : int  199 253 97 276 15 119 100 89 274 104 ...
 $ RowNum_OG        : int  1 2 3 4 5 6 7 8 9 10 ...
 $ StopID_New       : int  NA NA NA NA NA NA NA NA NA NA ...
 $ StopID_Clean     : chr  "5004572" "5004572" "5004573" "5002210" ...
 $ StopID_Indicator : Factor w/ 2 levels "ID_Bad","ID_OK": 2 2 2 2 2 2 2 2 2 2 ...
# View(tail(AllDays_StopIDNew, 500))
# View(filter(AllDays_StopIDNew,
#             Stop_Desc == "METROWAY ANNNOUCEMNT CORR"
#            )
#     )

Feature engineering.

Inspecting incidences of consecutive Stop_IDs. This is done because investigation showed that many conseutive events occurr at the same Stop_ID, but with various Dwell_Times, Odometer_Distances, etc. All of which affect calculations and analyses.

Create data on the runs (consecutive Stop_IDs).

StopID_Runs <- rle(AllDays_StopIDNew$StopID_Clean)
StopID_Runs$ends <- cumsum(StopID_Runs$lengths)
StopID_Runs$starts <- ifelse(is.na(lag(StopID_Runs$ends)
                                  ),
                             1,
                             lag(StopID_Runs$ends) + 1
                            )
str(StopID_Runs)
List of 4
 $ lengths: int [1:2809529] 2 1 1 1 1 2 1 1 1 1 ...
 $ values : chr [1:2809529] "5004572" "5004573" "5002210" "5002209" ...
 $ ends   : int [1:2809529] 2 3 4 5 6 8 9 10 11 12 ...
 $ starts : num [1:2809529] 1 3 4 5 6 7 9 10 11 12 ...
 - attr(*, "class")= chr "rle"
# class(StopID_Runs)
# 
# StopID_Runs_df <- data.frame(unclass(StopID_Runs))
# str(StopID_Runs_df)
# class(StopID_Runs_df)
# rm(StopID_Runs_df)

Trying to link data on RunsGroups with the original data (AllDays_Sorted). The goal is to select only one record per RunsGroup - that being the record with the longest Dwell_Time.

I attempted this computation using both data.frames (dplyr) and data.tables (data.table). However, with 2,809,062 rows in one dataset and 3,119,443 rows in the other dataset, the current computation time is over 5 days…so I’m trying a different strategy to only select the first record in a run.

# Create a RunsGroup variable for each run
# StopID_Runs_df$RunsGroup <- paste0("g", seq(1:nrow(StopID_Runs_df)
#                                            )
#                                   )
# 
# str(StopID_Runs_df)
# head(StopID_Runs_df, 25)
# tail(StopID_Runs_df, 25)
# 
# StopID_Runs_df <- StopID_Runs_df %>% 
#   mutate(RowNum = row_number()
#         )
# 
# str(StopID_Runs_df)
# head(StopID_Runs_df, 25)
# tail(StopID_Runs_df, 25)
# 
# 
# # Converting to data.tables for, hopefully, improved performance (speed) in computation
# StopID_Runs_dt <- data.table(StopID_Runs_df)
# setkey(StopID_Runs_dt, RowNum)
# str(StopID_Runs_dt)
# 
# AllDays_Sorted_dt <- data.table(AllDays_Sorted)
# setkey(AllDays_Sorted_dt, RowNum_OG)
# str(AllDays_Sorted_dt)
# # rm(AllDays_Sorted_dt)
# 
# 
# # Actual loop to perform the computations and link to original data (AllDays_Sorted_dt)
# GroupData <- list()
# for(i in 1:nrow(StopID_Runs_dt)
#    ) {
#   assign(paste0("group_", i),
#            StopID_Runs_dt[RowNum == i, RunsGroup]
#           )
# 
#     #####  The code below is the same code as above, but done with dplyr  #####
# 
#     # assign(paste0("group_", i),
#   #        filter(StopID_Runs_df,
#   #               RowNum == i
#   #              ) %>% 
#   #          select(RunsGroup)
#   #       )
# 
#   assign(paste0("group_", i, "_start"),
#          StopID_Runs_dt[RowNum == i, starts]
#         )
# 
#   assign(paste0("group_", i, "_end"),
#          StopID_Runs_dt[RowNum == i, ends]
#         )
# 
#   assign(paste0("group_", i, "_rows"),
#          AllDays_Sorted_dt[RowNum_OG >= as.numeric(get(paste0("group_", i, "_start")
#                                                       )
#                                                   ) &
#                            RowNum_OG <= as.numeric(get(paste0("group_", i, "_end")
#                                                       )
#                                                   ),
#                            RunsGroup := as.character(get(paste0("group_", i)
#                                                         )
#                                                     )
#                           ]
# 
#     #####  The code below is the same as the code above, but done with dplyr  #####
# 
#          # filter(AllDays_Sorted,
#          #        between(RowNum_OG,
#          #                as.numeric(get(paste0("group_", i, "_start")
#          #                              )
#          #                          ),
#          #                as.numeric(get(paste0("group_", i, "_end")
#          #                              )
#          #                          )
#          #               )
#          #       ) %>% 
#          #   mutate(RunsGroup = as.character(get(paste0("group_", i)
#          #                                     )
#          #                                 )
#          #        )
#         )
# 
#   GroupData[[i]] <- get(paste0("group_", i, "_rows"))
# 
#   message("Processing Group ", i, " of 2,809,062")
# }
# 
# 
# GroupData_df <- rbind.fill(GroupData)
# str(GroupData_df)
# head(GroupData_df)
# tail(GroupData_df)
# # rm(GroupData_df)
# 
# 
# group_1
# group_1_start
# group_1_end
# group_1_rows
# group_2_rows
# group_3_rows
# group_50_rows
# str(group_50_rows)
# group_2809062_rows
# GroupData[[1]]
# GroupData[[50]]
# 
# 
# #####  Testing Area (Below)  #####
# #####  Testing Area (Below)  #####
# #####  Testing Area (Below)  #####
# 
# # head(StopID_Runs$starts, 20)
# # head(AllDays_NewOrder$Stop_ID, 20)
# # 
# # 
# # dat <- as.data.frame(c(1,1,7,7,7,9,6,8,2,2,2,1,1,1,1,1))
# # colnames(dat)[1] <- "dat"
# # r <- rle(dat$dat)
# # dat$run <- rep(r$lengths, r$lengths)
# # dat$runLag <- lag(dat$run)
# # dat$cond <- rep(r$values, r$lengths)
# # dat
# # View(dat)

When consecutive Stop_ID occurrs, only take the first occurrence. This is done because the computation time to select only the record with the longest Dwell_Time for each run was too long (over 5 days).

This is probably less than ideal with regards to Dwell_Time, but should not make much difference for calculations of travel time, speed, etc.

AllDays_FirstStopID <- AllDays_StopIDNew[StopID_Runs$starts, ]
dim(AllDays_StopIDNew)
[1] 3119443      22
dim(AllDays_FirstStopID)
[1] 2809529      22
nrow(AllDays_StopIDNew) - nrow(AllDays_FirstStopID)
[1] 309914
rm(AllDays_StopIDNew)
rm(StopID_Runs)
str(AllDays_FirstStopID)
'data.frame':   2809529 obs. of  22 variables:
 $ group            : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Bus_ID           : int  11 11 11 11 11 11 11 11 11 11 ...
 $ Route            : chr  "S80" "S80" "S80" "S80" ...
 $ RouteAlt         : Factor w/ 14 levels "1","10","11",..: 1 1 1 1 1 1 6 6 6 6 ...
 $ Route_Direction  : Factor w/ 12 levels "","ANTICLKW",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ Stop_Sequence    : int  7 6 3 2 8 1 2 3 4 2 ...
 $ Stop_ID          : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ Stop_Desc        : chr  "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" "BEULAH ST + CHARLES ARRINGTON DR" ...
 $ Event_Type       : int  4 4 4 4 3 3 4 4 4 4 ...
 $ Event_Description: Factor w/ 3 levels "Serviced Stop                                     ",..: 3 3 3 3 1 1 3 3 3 3 ...
 $ Event_Time       : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Departure_Time   : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Dwell_Time       : int  0 0 0 0 0 104 0 0 0 0 ...
 $ Delta_Time       : int  -177 24 165 25 73 719 74 76 63 69 ...
 $ Odometer_Distance: int  43543 45139 46418 50115 51074 51303 55633 56163 56285 57262 ...
 $ Latitude         : num  38.8 38.8 38.8 38.8 38.8 ...
 $ Longitude        : num  -77.2 -77.2 -77.2 -77.2 -77.2 ...
 $ Heading          : int  199 97 276 15 119 100 274 104 241 274 ...
 $ RowNum_OG        : int  1 3 4 5 6 7 9 10 11 12 ...
 $ StopID_New       : int  NA NA NA NA NA NA NA NA NA NA ...
 $ StopID_Clean     : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ StopID_Indicator : Factor w/ 2 levels "ID_Bad","ID_OK": 2 2 2 2 2 2 2 2 2 2 ...

Feature engineering.

Creating new variables.

AllDays_AddVars <- mutate(AllDays_FirstStopID,
                          Odometer_Distance_Mi = Odometer_Distance / 5280, #5,280 feet in 1 mile
                          Dwell_Time2 = as.numeric(Departure_Time - Event_Time),
                          Event_Time_Yr = as.integer(year(Event_Time)),
                          Event_Time_Mth = as.integer(month(Event_Time)),
                          Event_Time_Date = day(Event_Time),
                          Event_Time_Day = wday(Event_Time, label = TRUE),
                          Event_Time_Hr = hour(Event_Time),
                          Event_Time_Min = minute(Event_Time),
                          Event_Time_HrGroup = factor(ifelse(Event_Time_Hr < 3,
                                                             "Group0_2",
                                                      ifelse(Event_Time_Hr < 6,
                                                             "Group3_5",
                                                      ifelse(Event_Time_Hr < 9,
                                                             "Group6_8",
                                                      ifelse(Event_Time_Hr < 12,
                                                             "Group9_11",
                                                      ifelse(Event_Time_Hr < 15,
                                                             "Group12_14",
                                                      ifelse(Event_Time_Hr < 18,
                                                             "Group15_17",
                                                      ifelse(Event_Time_Hr < 21,
                                                             "Group18_20",
                                                      ifelse(Event_Time_Hr < 24,
                                                             "Group21_23"
                                                            )))))))),
                                                         levels = c("Group0_2",
                                                                    "Group3_5",
                                                                    "Group6_8",
                                                                    "Group9_11",
                                                                    "Group12_14",
                                                                    "Group15_17",
                                                                    "Group18_20",
                                                                    "Group21_23"
                                                                   ),
                                                         ordered = TRUE
                                                     )
                         )
rm(AllDays_FirstStopID)
str(AllDays_AddVars)
'data.frame':   2809529 obs. of  31 variables:
 $ group               : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Bus_ID              : int  11 11 11 11 11 11 11 11 11 11 ...
 $ Route               : chr  "S80" "S80" "S80" "S80" ...
 $ RouteAlt            : Factor w/ 14 levels "1","10","11",..: 1 1 1 1 1 1 6 6 6 6 ...
 $ Route_Direction     : Factor w/ 12 levels "","ANTICLKW",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ Stop_Sequence       : int  7 6 3 2 8 1 2 3 4 2 ...
 $ Stop_ID             : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ Stop_Desc           : chr  "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" "BEULAH ST + CHARLES ARRINGTON DR" ...
 $ Event_Type          : int  4 4 4 4 3 3 4 4 4 4 ...
 $ Event_Description   : Factor w/ 3 levels "Serviced Stop                                     ",..: 3 3 3 3 1 1 3 3 3 3 ...
 $ Event_Time          : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Departure_Time      : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Dwell_Time          : int  0 0 0 0 0 104 0 0 0 0 ...
 $ Delta_Time          : int  -177 24 165 25 73 719 74 76 63 69 ...
 $ Odometer_Distance   : int  43543 45139 46418 50115 51074 51303 55633 56163 56285 57262 ...
 $ Latitude            : num  38.8 38.8 38.8 38.8 38.8 ...
 $ Longitude           : num  -77.2 -77.2 -77.2 -77.2 -77.2 ...
 $ Heading             : int  199 97 276 15 119 100 274 104 241 274 ...
 $ RowNum_OG           : int  1 3 4 5 6 7 9 10 11 12 ...
 $ StopID_New          : int  NA NA NA NA NA NA NA NA NA NA ...
 $ StopID_Clean        : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ StopID_Indicator    : Factor w/ 2 levels "ID_Bad","ID_OK": 2 2 2 2 2 2 2 2 2 2 ...
 $ Odometer_Distance_Mi: num  8.25 8.55 8.79 9.49 9.67 ...
 $ Dwell_Time2         : num  0 0 0 0 0 104 0 0 0 0 ...
 $ Event_Time_Yr       : int  2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
 $ Event_Time_Mth      : int  10 10 10 10 10 10 10 10 10 10 ...
 $ Event_Time_Date     : int  3 3 3 3 3 3 3 3 3 3 ...
 $ Event_Time_Day      : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
 $ Event_Time_Hr       : int  6 6 6 6 6 6 6 6 6 6 ...
 $ Event_Time_Min      : int  6 9 10 10 13 14 21 21 23 23 ...
 $ Event_Time_HrGroup  : Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 3 3 3 3 3 3 3 3 3 3 ...
# group_by(AllDays_AddVars,
#          Event_Time_HrGroup
#         ) %>% 
#   summarise(Cnts = n()
#            )
# View(head(filter(AllDays_AddVars,
#                  Event_Time_Hr == 0
#                 ),
#           50
#          )
#     )
# View(head(AllDays_AddVars, 50))

Feature engineering.

Creating more variables. Creating a BusEvent row number for future identification purposes. Then, creating various variables to analyze distance traveled and speed.

AllDays_BusDay <- group_by(AllDays_AddVars,
                           Bus_ID,
                           Event_Time_Date
                          ) %>% 
  mutate(BusDay_EventNum = row_number(),  # used to identify Bus movements on a particular date
         
         Odometer_Distance_Lag1 = lag(Odometer_Distance),
         
         Latitude_L1 = lag(Latitude),
         Longitude_L1 = lag(Longitude),
         # Lat_Radian = Latitude*pi/180,
         # Long_Radian = Longitude*pi/180,
         # Lat_Radian_L1 = lag(Lat_Radian),
         # Long_Radian_L1 = lag(Long_Radian),
         
         # accounting for potential negative distances
         TravelDistance_Ft = ifelse(Odometer_Distance > Odometer_Distance_Lag1,
                                    Odometer_Distance - Odometer_Distance_Lag1,
                                    NA
                                   ),
         TravelDistance_Mi = TravelDistance_Ft / 5280, #5,280 feet in 1 mile
         
         # TravelDistance_Mi2 = gcd.hf(long1 = Long_Radian_L1,
         #                             lat1 = Lat_Radian_L1,
         #                             long2 = Long_Radian,
         #                             lat2 = Lat_Radian
         #                            ),
         
         TravelDistance_Mi_Hvrs = 
                              # ifelse((is.na(Longitude_L1) | is.na(Latitude_L1)
                              #        ),
                              #        NA,
                              distHaversine(cbind(Longitude_L1, Latitude_L1),
                                            cbind(Longitude, Latitude)
                                           ) * 0.000621371, # 0.000621371 miles = 1 meter
         
         # accounting for potential negative times
         TravelTime_Sec = as.numeric(ifelse(Event_Time > lag(Departure_Time),
                                            Event_Time - lag(Departure_Time),
                                            NA
                                           )
                                    ),
         TravelTime_Hr = TravelTime_Sec / 3600, # 3,600 seconds in 1 hour
         
         # accounting for potential negative or zero travel times
         SpeedAvg_Mph = ifelse(TravelTime_Hr > 0,
                               TravelDistance_Mi / TravelTime_Hr,
                               NA
                              ),
         
         Start_ID = lag(StopID_Clean),
         Start_Desc = lag(Stop_Desc),
         StartStop_ID = ifelse(is.na(Start_ID),
                               paste("NULL", StopID_Clean, sep = "--"),
                               paste(Start_ID, StopID_Clean, sep = "--")
                              )
        ) %>% 
  as.data.frame()

Inspecting for issues with StartStop_ID (where the value is either NA or contains NULL). They ONLY exist when BusDay_EventNum = 1 (which is by design). So everything looks OK.

View(group_by(AllDays_BusDay,
              StartStop_ID
             ) %>% 
       summarise(
         Cnt = n()
       ) %>% 
       arrange(desc(Cnt)
              )
    )
View(filter(AllDays_BusDay,
            (is.na(StartStop_ID) |
              str_detect(StartStop_ID, "NULL")
            ) &
              BusDay_EventNum != 1
           )
    )

Stats for StartStop_ID.

Quantiles_SS_dt <- group_by(AllDays_BusDay,
                            StartStop_ID
                           ) %>% 
  mutate(TD_Mi_SS_q5 = quantile(x = TravelDistance_Mi, probs = 0.05, na.rm = TRUE),
         TD_Mi_SS_q95 = quantile(x = TravelDistance_Mi, probs = 0.95, na.rm = TRUE),
         TT_Sec_SS_q5 = quantile(x = TravelTime_Sec, probs = 0.05, na.rm = TRUE),
         TT_Sec_SS_q95 = quantile(x = TravelTime_Sec, probs = 0.95, na.rm = TRUE),
         TT_Hr_SS_q5 = quantile(x = TravelTime_Hr, probs = 0.05, na.rm = TRUE),
         TT_Hr_SS_q95 = quantile(x = TravelTime_Hr, probs = 0.95, na.rm = TRUE)
        ) %>% 
  data.table()

Stats for StartStop_ID with Event_Time_HrGroup.

Quantiles_SSHG_dt <- group_by(Stats_StSt,
                              StartStop_ID,
                              Event_Time_HrGroup
                             ) %>% 
  mutate(TD_Mi_SSHG_q5 = quantile(x = TravelDistance_Mi, probs = 0.05, na.rm = TRUE),
         TD_Mi_SSHG_q95 = quantile(x = TravelDistance_Mi, probs = 0.95, na.rm = TRUE),
         TT_Sec_SSHG_q5 = quantile(x = TravelTime_Sec, probs = 0.05, na.rm = TRUE),
         TT_Sec_SSHG_q95 = quantile(x = TravelTime_Sec, probs = 0.95, na.rm = TRUE),
         TT_Hr_SSHG_q5 = quantile(x = TravelTime_Hr, probs = 0.05, na.rm = TRUE),
         TT_Hr_SSHG_q95 = quantile(x = TravelTime_Hr, probs = 0.95, na.rm = TRUE)
        ) %>% 
  data.table()

Feature engineering.

Creating a BusEventRoute row number, and a RouteAlt_Lag1 indicator for future identification purposes.

AllDays_BusDayRoute <- group_by(Stats_StSt_HrGrp,
                                Bus_ID,
                                Event_Time_Date,
                                Route
                               ) %>% 
  mutate(RouteAlt_Lag1 = lag(RouteAlt)  # used in future analyses to identify Route changes
         # Odometer_Distance_Lag1 = lag(Odometer_Distance),
         # 
         # # accounting for potential negative distances
         # TravelDistance_Ft = ifelse(Odometer_Distance >= Odometer_Distance_Lag1,
         #                            Odometer_Distance - Odometer_Distance_Lag1,
         #                            NA
         #                           ),
         # TravelDistance_Mi = TravelDistance_Ft / 5280, #5,280 feet in 1 mile
         # 
         # # accounting for potential negative times
         # TravelTime_Sec = as.numeric(ifelse(Event_Time >= lag(Departure_Time),
         #                                    Event_Time - lag(Departure_Time),
         #                                    NA
         #                                   )
         #                            ),
         # TravelTime_Hr = TravelTime_Sec / 3600, # 3,600 seconds in 1 hour
         # 
         # # accounting for potential negative or zero travel times
         # SpeedAvg_Mph = ifelse(TravelTime_Hr > 0,
         #                       TravelDistance_Mi / TravelTime_Hr,
         #                       NA
         #                      )
        ) %>% 
  data.frame()
str(AllDays_BusDayRoute)
'data.frame':   2809529 obs. of  93 variables:
 $ group                 : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Bus_ID                : int  11 11 11 11 11 11 11 11 11 11 ...
 $ Route                 : chr  "S80" "S80" "S80" "S80" ...
 $ RouteAlt              : Factor w/ 14 levels "1","10","11",..: 1 1 1 1 1 1 6 6 6 6 ...
 $ Route_Direction       : Factor w/ 12 levels "","ANTICLKW",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ Stop_Sequence         : int  7 6 3 2 8 1 2 3 4 2 ...
 $ Stop_ID               : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ Stop_Desc             : chr  "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" "BEULAH ST + CHARLES ARRINGTON DR" ...
 $ Event_Type            : int  4 4 4 4 3 3 4 4 4 4 ...
 $ Event_Description     : Factor w/ 3 levels "Serviced Stop                                     ",..: 3 3 3 3 1 1 3 3 3 3 ...
 $ Event_Time            : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Departure_Time        : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Dwell_Time            : int  0 0 0 0 0 104 0 0 0 0 ...
 $ Delta_Time            : int  -177 24 165 25 73 719 74 76 63 69 ...
 $ Odometer_Distance     : int  43543 45139 46418 50115 51074 51303 55633 56163 56285 57262 ...
 $ Latitude              : num  38.8 38.8 38.8 38.8 38.8 ...
 $ Longitude             : num  -77.2 -77.2 -77.2 -77.2 -77.2 ...
 $ Heading               : int  199 97 276 15 119 100 274 104 241 274 ...
 $ RowNum_OG             : int  1 3 4 5 6 7 9 10 11 12 ...
 $ StopID_New            : int  NA NA NA NA NA NA NA NA NA NA ...
 $ StopID_Clean          : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ StopID_Indicator      : Factor w/ 2 levels "ID_Bad","ID_OK": 2 2 2 2 2 2 2 2 2 2 ...
 $ Odometer_Distance_Mi  : num  8.25 8.55 8.79 9.49 9.67 ...
 $ Dwell_Time2           : num  0 0 0 0 0 104 0 0 0 0 ...
 $ Event_Time_Yr         : int  2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
 $ Event_Time_Mth        : int  10 10 10 10 10 10 10 10 10 10 ...
 $ Event_Time_Date       : int  3 3 3 3 3 3 3 3 3 3 ...
 $ Event_Time_Day        : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
 $ Event_Time_Hr         : int  6 6 6 6 6 6 6 6 6 6 ...
 $ Event_Time_Min        : int  6 9 10 10 13 14 21 21 23 23 ...
 $ Event_Time_HrGroup    : Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 3 3 3 3 3 3 3 3 3 3 ...
 $ BusDay_EventNum       : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Odometer_Distance_Lag1: int  NA 43543 45139 46418 50115 51074 51303 55633 56163 56285 ...
 $ Latitude_L1           : num  NA 38.8 38.8 38.8 38.8 ...
 $ Longitude_L1          : num  NA -77.2 -77.2 -77.2 -77.2 ...
 $ TravelDistance_Ft     : int  NA 1596 1279 3697 959 229 4330 530 122 977 ...
 $ TravelDistance_Mi     : num  NA 0.302 0.242 0.7 0.182 ...
 $ TravelDistance_Mi_Hvrs: num  NA 0.15 0.105 0.165 0.832 ...
 $ TravelTime_Sec        : num  NA 180 37 25 190 29 288 52 76 8 ...
 $ TravelTime_Hr         : num  NA 0.05 0.01028 0.00694 0.05278 ...
 $ SpeedAvg_Mph          : num  NA 6.05 23.57 100.83 3.44 ...
 $ Start_ID              : chr  NA "5004572" "5004573" "5002210" ...
 $ Start_Desc            : chr  NA "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" ...
 $ StartStop_ID          : chr  "NULL--5004572" "5004572--5004573" "5004573--5002210" "5002210--5002209" ...
 $ TD_Mi_SS_q5           : num  NA 0.0252 0.2422 0.7324 0.0794 ...
 $ TD_Mi_SS_q95          : num  NA 0.626 0.242 1.008 0.176 ...
 $ TT_Sec_SS_q5          : num  NA 11.9 37 30.5 172.9 ...
 $ TT_Sec_SS_q95         : num  NA 346.3 37 75.8 189.1 ...
 $ TT_Hr_SS_q5           : num  NA 0.00331 0.01028 0.00849 0.04803 ...
 $ TT_Hr_SS_q95          : num  NA 0.0962 0.0103 0.0211 0.0525 ...
 $ TD_Mi_SS_Mean         : num  NaN 0.437 0.242 0.908 0.128 ...
 $ TD_Mi_SS_Mean_F       : num  NaN 0.457 0.242 0.977 NaN ...
 $ TD_Mi_SS_Med          : num  NA 0.512 0.242 0.962 0.128 ...
 $ TD_Mi_SS_Med_F        : num  NA 0.512 0.242 1.008 NA ...
 $ TD_Mi_SS_Cnt          : int  0 14 1 4 2 87 22 118 91 11 ...
 $ TD_Mi_SS_Cnt_F        : int  0 12 1 3 0 77 18 106 81 9 ...
 $ TT_Sec_SS_Mean        : num  NaN 215.8 37 58.2 181 ...
 $ TT_Sec_SS_Mean_F      : num  NaN 218.9 37 65.5 NaN ...
 $ TT_Sec_SS_Med         : num  NA 223.5 37 65.5 181 ...
 $ TT_Sec_SS_Med_F       : num  NA 223.5 37 65.5 NA ...
 $ TT_Sec_SS_Cnt         : int  0 14 1 4 2 173 22 141 141 11 ...
 $ TT_Sec_SS_Cnt_F       : int  0 12 1 2 0 156 18 127 128 9 ...
 $ TT_Hr_SS_Mean         : num  NaN 0.0599 0.0103 0.0162 0.0503 ...
 $ TT_Hr_SS_Mean_F       : num  NaN 0.0608 0.0103 0.0182 NaN ...
 $ TT_Hr_SS_Med          : num  NA 0.0621 0.0103 0.0182 0.0503 ...
 $ TT_Hr_SS_Med_F        : num  NA 0.0621 0.0103 0.0182 NA ...
 $ TT_Hr_SS_Cnt          : int  0 14 1 4 2 173 22 141 141 11 ...
 $ TT_Hr_SS_Cnt_F        : int  0 12 1 2 0 156 18 127 128 9 ...
 $ TD_Mi_SSHG_q5         : num  NA 0.0996 0.2422 0.7002 0.1816 ...
 $ TD_Mi_SSHG_q95        : num  NA 0.627 0.242 0.7 0.182 ...
 $ TT_Sec_SSHG_q5        : num  NA 59.6 37 25 190 11.6 236 51.5 55 8.8 ...
 $ TT_Sec_SSHG_q95       : num  NA 276 37 25 190 ...
 $ TT_Hr_SSHG_q5         : num  NA 0.01656 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_q95        : num  NA 0.07653 0.01028 0.00694 0.05278 ...
 $ TD_Mi_SSHG_Mean       : num  NaN 0.442 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Mean_F     : num  NaN 0.491 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Med        : num  NA 0.512 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Med_F      : num  NA 0.512 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Cnt        : int  0 7 1 1 1 23 6 29 28 3 ...
 $ TD_Mi_SSHG_Cnt_F      : int  0 5 1 1 1 19 4 25 24 1 ...
 $ TT_Sec_SSHG_Mean      : num  NaN 202 37 25 190 ...
 $ TT_Sec_SSHG_Mean_F    : num  NaN 226 37 25 190 ...
 $ TT_Sec_SSHG_Med       : num  NA 219 37 25 190 134 286 60 65 16 ...
 $ TT_Sec_SSHG_Med_F     : num  NA 219 37 25 190 134 286 60 65 16 ...
 $ TT_Sec_SSHG_Cnt       : int  0 7 1 1 1 35 6 36 35 3 ...
 $ TT_Sec_SSHG_Cnt_F     : int  0 5 1 1 1 31 4 32 32 1 ...
 $ TT_Hr_SSHG_Mean       : num  NaN 0.05615 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Mean_F     : num  NaN 0.06278 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Med        : num  NA 0.06083 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Med_F      : num  NA 0.06083 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Cnt        : int  0 7 1 1 1 35 6 36 35 3 ...
 $ TT_Hr_SSHG_Cnt_F      : int  0 5 1 1 1 31 4 32 28 1 ...
 $ RouteAlt_Lag1         : Factor w/ 14 levels "1","10","11",..: NA 1 1 1 1 1 1 6 6 6 ...

Feature engineering.

Calculating a variable to know if the RouteAlt changed. Could be useful in helping identifying weirdness in calculated distances and speeds.

rm(Stats_StSt_HrGrp)
AllDays_DirChange <- AllDays_BusDayRoute %>% 
  mutate(DirChange = ifelse(RouteAlt == RouteAlt_Lag1,
                            "Same",
                            "Change"
                           ),
         DirChange2 = factor(ifelse(is.na(DirChange),
                                    "Change",
                                    DirChange
                                   )
                            )
        )
str(AllDays_DirChange)
'data.frame':   2809529 obs. of  95 variables:
 $ group                 : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Bus_ID                : int  11 11 11 11 11 11 11 11 11 11 ...
 $ Route                 : chr  "S80" "S80" "S80" "S80" ...
 $ RouteAlt              : Factor w/ 14 levels "1","10","11",..: 1 1 1 1 1 1 6 6 6 6 ...
 $ Route_Direction       : Factor w/ 12 levels "","ANTICLKW",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ Stop_Sequence         : int  7 6 3 2 8 1 2 3 4 2 ...
 $ Stop_ID               : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ Stop_Desc             : chr  "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" "BEULAH ST + CHARLES ARRINGTON DR" ...
 $ Event_Type            : int  4 4 4 4 3 3 4 4 4 4 ...
 $ Event_Description     : Factor w/ 3 levels "Serviced Stop                                     ",..: 3 3 3 3 1 1 3 3 3 3 ...
 $ Event_Time            : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Departure_Time        : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Dwell_Time            : int  0 0 0 0 0 104 0 0 0 0 ...
 $ Delta_Time            : int  -177 24 165 25 73 719 74 76 63 69 ...
 $ Odometer_Distance     : int  43543 45139 46418 50115 51074 51303 55633 56163 56285 57262 ...
 $ Latitude              : num  38.8 38.8 38.8 38.8 38.8 ...
 $ Longitude             : num  -77.2 -77.2 -77.2 -77.2 -77.2 ...
 $ Heading               : int  199 97 276 15 119 100 274 104 241 274 ...
 $ RowNum_OG             : int  1 3 4 5 6 7 9 10 11 12 ...
 $ StopID_New            : int  NA NA NA NA NA NA NA NA NA NA ...
 $ StopID_Clean          : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ StopID_Indicator      : Factor w/ 2 levels "ID_Bad","ID_OK": 2 2 2 2 2 2 2 2 2 2 ...
 $ Odometer_Distance_Mi  : num  8.25 8.55 8.79 9.49 9.67 ...
 $ Dwell_Time2           : num  0 0 0 0 0 104 0 0 0 0 ...
 $ Event_Time_Yr         : int  2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
 $ Event_Time_Mth        : int  10 10 10 10 10 10 10 10 10 10 ...
 $ Event_Time_Date       : int  3 3 3 3 3 3 3 3 3 3 ...
 $ Event_Time_Day        : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
 $ Event_Time_Hr         : int  6 6 6 6 6 6 6 6 6 6 ...
 $ Event_Time_Min        : int  6 9 10 10 13 14 21 21 23 23 ...
 $ Event_Time_HrGroup    : Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 3 3 3 3 3 3 3 3 3 3 ...
 $ BusDay_EventNum       : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Odometer_Distance_Lag1: int  NA 43543 45139 46418 50115 51074 51303 55633 56163 56285 ...
 $ Latitude_L1           : num  NA 38.8 38.8 38.8 38.8 ...
 $ Longitude_L1          : num  NA -77.2 -77.2 -77.2 -77.2 ...
 $ TravelDistance_Ft     : int  NA 1596 1279 3697 959 229 4330 530 122 977 ...
 $ TravelDistance_Mi     : num  NA 0.302 0.242 0.7 0.182 ...
 $ TravelDistance_Mi_Hvrs: num  NA 0.15 0.105 0.165 0.832 ...
 $ TravelTime_Sec        : num  NA 180 37 25 190 29 288 52 76 8 ...
 $ TravelTime_Hr         : num  NA 0.05 0.01028 0.00694 0.05278 ...
 $ SpeedAvg_Mph          : num  NA 6.05 23.57 100.83 3.44 ...
 $ Start_ID              : chr  NA "5004572" "5004573" "5002210" ...
 $ Start_Desc            : chr  NA "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" ...
 $ StartStop_ID          : chr  "NULL--5004572" "5004572--5004573" "5004573--5002210" "5002210--5002209" ...
 $ TD_Mi_SS_q5           : num  NA 0.0252 0.2422 0.7324 0.0794 ...
 $ TD_Mi_SS_q95          : num  NA 0.626 0.242 1.008 0.176 ...
 $ TT_Sec_SS_q5          : num  NA 11.9 37 30.5 172.9 ...
 $ TT_Sec_SS_q95         : num  NA 346.3 37 75.8 189.1 ...
 $ TT_Hr_SS_q5           : num  NA 0.00331 0.01028 0.00849 0.04803 ...
 $ TT_Hr_SS_q95          : num  NA 0.0962 0.0103 0.0211 0.0525 ...
 $ TD_Mi_SS_Mean         : num  NaN 0.437 0.242 0.908 0.128 ...
 $ TD_Mi_SS_Mean_F       : num  NaN 0.457 0.242 0.977 NaN ...
 $ TD_Mi_SS_Med          : num  NA 0.512 0.242 0.962 0.128 ...
 $ TD_Mi_SS_Med_F        : num  NA 0.512 0.242 1.008 NA ...
 $ TD_Mi_SS_Cnt          : int  0 14 1 4 2 87 22 118 91 11 ...
 $ TD_Mi_SS_Cnt_F        : int  0 12 1 3 0 77 18 106 81 9 ...
 $ TT_Sec_SS_Mean        : num  NaN 215.8 37 58.2 181 ...
 $ TT_Sec_SS_Mean_F      : num  NaN 218.9 37 65.5 NaN ...
 $ TT_Sec_SS_Med         : num  NA 223.5 37 65.5 181 ...
 $ TT_Sec_SS_Med_F       : num  NA 223.5 37 65.5 NA ...
 $ TT_Sec_SS_Cnt         : int  0 14 1 4 2 173 22 141 141 11 ...
 $ TT_Sec_SS_Cnt_F       : int  0 12 1 2 0 156 18 127 128 9 ...
 $ TT_Hr_SS_Mean         : num  NaN 0.0599 0.0103 0.0162 0.0503 ...
 $ TT_Hr_SS_Mean_F       : num  NaN 0.0608 0.0103 0.0182 NaN ...
 $ TT_Hr_SS_Med          : num  NA 0.0621 0.0103 0.0182 0.0503 ...
 $ TT_Hr_SS_Med_F        : num  NA 0.0621 0.0103 0.0182 NA ...
 $ TT_Hr_SS_Cnt          : int  0 14 1 4 2 173 22 141 141 11 ...
 $ TT_Hr_SS_Cnt_F        : int  0 12 1 2 0 156 18 127 128 9 ...
 $ TD_Mi_SSHG_q5         : num  NA 0.0996 0.2422 0.7002 0.1816 ...
 $ TD_Mi_SSHG_q95        : num  NA 0.627 0.242 0.7 0.182 ...
 $ TT_Sec_SSHG_q5        : num  NA 59.6 37 25 190 11.6 236 51.5 55 8.8 ...
 $ TT_Sec_SSHG_q95       : num  NA 276 37 25 190 ...
 $ TT_Hr_SSHG_q5         : num  NA 0.01656 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_q95        : num  NA 0.07653 0.01028 0.00694 0.05278 ...
 $ TD_Mi_SSHG_Mean       : num  NaN 0.442 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Mean_F     : num  NaN 0.491 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Med        : num  NA 0.512 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Med_F      : num  NA 0.512 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Cnt        : int  0 7 1 1 1 23 6 29 28 3 ...
 $ TD_Mi_SSHG_Cnt_F      : int  0 5 1 1 1 19 4 25 24 1 ...
 $ TT_Sec_SSHG_Mean      : num  NaN 202 37 25 190 ...
 $ TT_Sec_SSHG_Mean_F    : num  NaN 226 37 25 190 ...
 $ TT_Sec_SSHG_Med       : num  NA 219 37 25 190 134 286 60 65 16 ...
 $ TT_Sec_SSHG_Med_F     : num  NA 219 37 25 190 134 286 60 65 16 ...
 $ TT_Sec_SSHG_Cnt       : int  0 7 1 1 1 35 6 36 35 3 ...
 $ TT_Sec_SSHG_Cnt_F     : int  0 5 1 1 1 31 4 32 32 1 ...
 $ TT_Hr_SSHG_Mean       : num  NaN 0.05615 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Mean_F     : num  NaN 0.06278 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Med        : num  NA 0.06083 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Med_F      : num  NA 0.06083 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Cnt        : int  0 7 1 1 1 35 6 36 35 3 ...
 $ TT_Hr_SSHG_Cnt_F      : int  0 5 1 1 1 31 4 32 28 1 ...
 $ RouteAlt_Lag1         : Factor w/ 14 levels "1","10","11",..: NA 1 1 1 1 1 1 6 6 6 ...
 $ DirChange             : chr  NA "Same" "Same" "Same" ...
 $ DirChange2            : Factor w/ 2 levels "Change","Same": 1 2 2 2 2 2 1 2 2 2 ...

Re-ordering the variables to ease with comprehension.

rm(AllDays_BusDayRoute)
AllDays_NewOrder <-  select(AllDays_DirChange,
                            RowNum_OG,
                            group,
                            StartStop_ID,
                            BusDay_EventNum,
                            Bus_ID,
                            Route,
                            RouteAlt,
                            # RouteAlt_Lag1,
                            DirChange2,
                            Route_Direction,
                            Stop_Sequence,
                            Start_ID,
                            Start_Desc,
                            # Stop_ID,
                            StopID_Clean,
                            StopID_Indicator,
                            Stop_Desc,
                            Event_Type,
                            Event_Description,
                            Event_Time_Yr,
                            Event_Time_Mth,
                            Event_Time_Date,
                            Event_Time_Day,
                            Event_Time_Hr,
                            Event_Time_HrGroup,
                            Event_Time_Min,
                            Event_Time,
                            Departure_Time,
                            Dwell_Time,
                            Dwell_Time2,
                            Delta_Time,
                            Latitude,
                            Longitude,
                            Heading,
                            Odometer_Distance,
                            Odometer_Distance_Lag1,
                            Odometer_Distance_Mi,
                            TravelDistance_Ft,
                            TravelDistance_Mi,
                            TravelDistance_Mi_Hvrs,
                            TD_Mi_SS_q5,
                            TD_Mi_SS_q95,
                            TD_Mi_SSHG_q5,
                            TD_Mi_SSHG_q95,
                            TD_Mi_SS_Mean,
                            TD_Mi_SS_Mean_F,
                            TD_Mi_SSHG_Mean,
                            TD_Mi_SSHG_Mean_F,
                            TD_Mi_SS_Med,
                            TD_Mi_SS_Med_F,
                            TD_Mi_SSHG_Med,
                            TD_Mi_SSHG_Med_F,
                            TD_Mi_SS_Cnt,
                            TD_Mi_SS_Cnt_F,
                            TD_Mi_SSHG_Cnt,
                            TD_Mi_SSHG_Cnt_F,
                            TravelTime_Sec,
                            TT_Sec_SS_q5,
                            TT_Sec_SS_q95,
                            TT_Sec_SSHG_q5,
                            TT_Sec_SSHG_q95,
                            TT_Sec_SS_Mean,
                            TT_Sec_SS_Mean_F,
                            TT_Sec_SSHG_Mean,
                            TT_Sec_SSHG_Mean_F,
                            TT_Sec_SS_Med,
                            TT_Sec_SS_Med_F,
                            TT_Sec_SSHG_Med,
                            TT_Sec_SSHG_Med_F,
                            TT_Sec_SS_Cnt,
                            TT_Sec_SS_Cnt_F,
                            TT_Sec_SSHG_Cnt,
                            TT_Sec_SSHG_Cnt_F,
                            TravelTime_Hr,
                            TT_Hr_SS_q5,
                            TT_Hr_SS_q95,
                            TT_Hr_SSHG_q5,
                            TT_Hr_SSHG_q95,
                            TT_Hr_SS_Mean,
                            TT_Hr_SS_Mean_F,
                            TT_Hr_SSHG_Mean,
                            TT_Hr_SSHG_Mean_F,
                            TT_Hr_SS_Med,
                            TT_Hr_SS_Med_F,
                            TT_Hr_SSHG_Med,
                            TT_Hr_SSHG_Med_F,
                            TT_Hr_SS_Cnt,
                            TT_Hr_SS_Cnt_F,
                            TT_Hr_SSHG_Cnt,
                            TT_Hr_SSHG_Cnt_F,
                            SpeedAvg_Mph
                           )
rm(AllDays_DirChange)
str(AllDays_NewOrder)
'data.frame':   2809529 obs. of  89 variables:
 $ RowNum_OG             : int  1 3 4 5 6 7 9 10 11 12 ...
 $ group                 : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ StartStop_ID          : chr  "NULL--5004572" "5004572--5004573" "5004573--5002210" "5002210--5002209" ...
 $ BusDay_EventNum       : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Bus_ID                : int  11 11 11 11 11 11 11 11 11 11 ...
 $ Route                 : chr  "S80" "S80" "S80" "S80" ...
 $ RouteAlt              : Factor w/ 14 levels "1","10","11",..: 1 1 1 1 1 1 6 6 6 6 ...
 $ DirChange2            : Factor w/ 2 levels "Change","Same": 1 2 2 2 2 2 1 2 2 2 ...
 $ Route_Direction       : Factor w/ 12 levels "","ANTICLKW",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ Stop_Sequence         : int  7 6 3 2 8 1 2 3 4 2 ...
 $ Start_ID              : chr  NA "5004572" "5004573" "5002210" ...
 $ Start_Desc            : chr  NA "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" ...
 $ StopID_Clean          : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ StopID_Indicator      : Factor w/ 2 levels "ID_Bad","ID_OK": 2 2 2 2 2 2 2 2 2 2 ...
 $ Stop_Desc             : chr  "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" "BEULAH ST + CHARLES ARRINGTON DR" ...
 $ Event_Type            : int  4 4 4 4 3 3 4 4 4 4 ...
 $ Event_Description     : Factor w/ 3 levels "Serviced Stop                                     ",..: 3 3 3 3 1 1 3 3 3 3 ...
 $ Event_Time_Yr         : int  2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
 $ Event_Time_Mth        : int  10 10 10 10 10 10 10 10 10 10 ...
 $ Event_Time_Date       : int  3 3 3 3 3 3 3 3 3 3 ...
 $ Event_Time_Day        : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
 $ Event_Time_Hr         : int  6 6 6 6 6 6 6 6 6 6 ...
 $ Event_Time_HrGroup    : Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 3 3 3 3 3 3 3 3 3 3 ...
 $ Event_Time_Min        : int  6 9 10 10 13 14 21 21 23 23 ...
 $ Event_Time            : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Departure_Time        : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Dwell_Time            : int  0 0 0 0 0 104 0 0 0 0 ...
 $ Dwell_Time2           : num  0 0 0 0 0 104 0 0 0 0 ...
 $ Delta_Time            : int  -177 24 165 25 73 719 74 76 63 69 ...
 $ Latitude              : num  38.8 38.8 38.8 38.8 38.8 ...
 $ Longitude             : num  -77.2 -77.2 -77.2 -77.2 -77.2 ...
 $ Heading               : int  199 97 276 15 119 100 274 104 241 274 ...
 $ Odometer_Distance     : int  43543 45139 46418 50115 51074 51303 55633 56163 56285 57262 ...
 $ Odometer_Distance_Lag1: int  NA 43543 45139 46418 50115 51074 51303 55633 56163 56285 ...
 $ Odometer_Distance_Mi  : num  8.25 8.55 8.79 9.49 9.67 ...
 $ TravelDistance_Ft     : int  NA 1596 1279 3697 959 229 4330 530 122 977 ...
 $ TravelDistance_Mi     : num  NA 0.302 0.242 0.7 0.182 ...
 $ TravelDistance_Mi_Hvrs: num  NA 0.15 0.105 0.165 0.832 ...
 $ TD_Mi_SS_q5           : num  NA 0.0252 0.2422 0.7324 0.0794 ...
 $ TD_Mi_SS_q95          : num  NA 0.626 0.242 1.008 0.176 ...
 $ TD_Mi_SSHG_q5         : num  NA 0.0996 0.2422 0.7002 0.1816 ...
 $ TD_Mi_SSHG_q95        : num  NA 0.627 0.242 0.7 0.182 ...
 $ TD_Mi_SS_Mean         : num  NaN 0.437 0.242 0.908 0.128 ...
 $ TD_Mi_SS_Mean_F       : num  NaN 0.457 0.242 0.977 NaN ...
 $ TD_Mi_SSHG_Mean       : num  NaN 0.442 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Mean_F     : num  NaN 0.491 0.242 0.7 0.182 ...
 $ TD_Mi_SS_Med          : num  NA 0.512 0.242 0.962 0.128 ...
 $ TD_Mi_SS_Med_F        : num  NA 0.512 0.242 1.008 NA ...
 $ TD_Mi_SSHG_Med        : num  NA 0.512 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Med_F      : num  NA 0.512 0.242 0.7 0.182 ...
 $ TD_Mi_SS_Cnt          : int  0 14 1 4 2 87 22 118 91 11 ...
 $ TD_Mi_SS_Cnt_F        : int  0 12 1 3 0 77 18 106 81 9 ...
 $ TD_Mi_SSHG_Cnt        : int  0 7 1 1 1 23 6 29 28 3 ...
 $ TD_Mi_SSHG_Cnt_F      : int  0 5 1 1 1 19 4 25 24 1 ...
 $ TravelTime_Sec        : num  NA 180 37 25 190 29 288 52 76 8 ...
 $ TT_Sec_SS_q5          : num  NA 11.9 37 30.5 172.9 ...
 $ TT_Sec_SS_q95         : num  NA 346.3 37 75.8 189.1 ...
 $ TT_Sec_SSHG_q5        : num  NA 59.6 37 25 190 11.6 236 51.5 55 8.8 ...
 $ TT_Sec_SSHG_q95       : num  NA 276 37 25 190 ...
 $ TT_Sec_SS_Mean        : num  NaN 215.8 37 58.2 181 ...
 $ TT_Sec_SS_Mean_F      : num  NaN 218.9 37 65.5 NaN ...
 $ TT_Sec_SSHG_Mean      : num  NaN 202 37 25 190 ...
 $ TT_Sec_SSHG_Mean_F    : num  NaN 226 37 25 190 ...
 $ TT_Sec_SS_Med         : num  NA 223.5 37 65.5 181 ...
 $ TT_Sec_SS_Med_F       : num  NA 223.5 37 65.5 NA ...
 $ TT_Sec_SSHG_Med       : num  NA 219 37 25 190 134 286 60 65 16 ...
 $ TT_Sec_SSHG_Med_F     : num  NA 219 37 25 190 134 286 60 65 16 ...
 $ TT_Sec_SS_Cnt         : int  0 14 1 4 2 173 22 141 141 11 ...
 $ TT_Sec_SS_Cnt_F       : int  0 12 1 2 0 156 18 127 128 9 ...
 $ TT_Sec_SSHG_Cnt       : int  0 7 1 1 1 35 6 36 35 3 ...
 $ TT_Sec_SSHG_Cnt_F     : int  0 5 1 1 1 31 4 32 32 1 ...
 $ TravelTime_Hr         : num  NA 0.05 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SS_q5           : num  NA 0.00331 0.01028 0.00849 0.04803 ...
 $ TT_Hr_SS_q95          : num  NA 0.0962 0.0103 0.0211 0.0525 ...
 $ TT_Hr_SSHG_q5         : num  NA 0.01656 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_q95        : num  NA 0.07653 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SS_Mean         : num  NaN 0.0599 0.0103 0.0162 0.0503 ...
 $ TT_Hr_SS_Mean_F       : num  NaN 0.0608 0.0103 0.0182 NaN ...
 $ TT_Hr_SSHG_Mean       : num  NaN 0.05615 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Mean_F     : num  NaN 0.06278 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SS_Med          : num  NA 0.0621 0.0103 0.0182 0.0503 ...
 $ TT_Hr_SS_Med_F        : num  NA 0.0621 0.0103 0.0182 NA ...
 $ TT_Hr_SSHG_Med        : num  NA 0.06083 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Med_F      : num  NA 0.06083 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SS_Cnt          : int  0 14 1 4 2 173 22 141 141 11 ...
 $ TT_Hr_SS_Cnt_F        : int  0 12 1 2 0 156 18 127 128 9 ...
 $ TT_Hr_SSHG_Cnt        : int  0 7 1 1 1 35 6 36 35 3 ...
 $ TT_Hr_SSHG_Cnt_F      : int  0 5 1 1 1 31 4 32 28 1 ...
 $ SpeedAvg_Mph          : num  NA 6.05 23.57 100.83 3.44 ...
# View(head(AllDays_NewOrder, 500))
View(tail(AllDays_NewOrder, 500))

Summarizing the data to help spot anomolies.

summary(AllDays_NewOrder)
   RowNum_OG       group      StartStop_ID       BusDay_EventNum      Bus_ID    
 Min.   :      1   1:559521   Length:2809529     Min.   :   1.0   Min.   :  11  
 1st Qu.: 784722   2:561389   Class :character   1st Qu.: 113.0   1st Qu.:2922  
 Median :1563300   3:567794   Mode  :character   Median : 248.0   Median :6195  
 Mean   :1562504   4:559180                      Mean   : 290.5   Mean   :5382  
 3rd Qu.:2337981   5:561645                      3rd Qu.: 428.0   3rd Qu.:7104  
 Max.   :3119443                                 Max.   :1344.0   Max.   :8105  
                                                                                
    Route              RouteAlt        DirChange2      Route_Direction  
 Length:2809529     2      :1128810   Change:  67071   SOUTH   :739235  
 Class :character   1      :1065425   Same  :2742458   NORTH   :735203  
 Mode  :character   3      : 260372                    WEST    :649706  
                    4      : 130801                    EAST    :628074  
                    5      :  75039                    LOOP    : 35611  
                    6      :  56408                    CLOCKWIS: 10671  
                    (Other):  92674                    (Other) : 11029  
 Stop_Sequence      Start_ID          Start_Desc        StopID_Clean      
 Min.   :  1.00   Length:2809529     Length:2809529     Length:2809529    
 1st Qu.: 12.00   Class :character   Class :character   Class :character  
 Median : 24.00   Mode  :character   Mode  :character   Mode  :character  
 Mean   : 26.83                                                           
 3rd Qu.: 39.00                                                           
 Max.   :104.00                                                           
                                                                          
 StopID_Indicator  Stop_Desc           Event_Type 
 ID_Bad:  18948   Length:2809529     Min.   :3.0  
 ID_OK :2790581   Class :character   1st Qu.:3.0  
                  Mode  :character   Median :4.0  
                                     Mean   :3.6  
                                     3rd Qu.:4.0  
                                     Max.   :5.0  
                                                  
                                          Event_Description   Event_Time_Yr 
 Serviced Stop                                     :1127366   Min.   :2016  
 Unknown Stop                                      :   2579   1st Qu.:2016  
 UnServiced Stop                                   :1679584   Median :2016  
                                                              Mean   :2016  
                                                              3rd Qu.:2016  
                                                              Max.   :2016  
                                                                            
 Event_Time_Mth Event_Time_Date Event_Time_Day Event_Time_Hr    Event_Time_HrGroup
 Min.   :10     Min.   :3.000   Sun  :     0   Min.   : 0.00   Group6_8  :611612  
 1st Qu.:10     1st Qu.:4.000   Mon  :559521   1st Qu.: 8.00   Group15_17:560103  
 Median :10     Median :5.000   Tues :561389   Median :13.00   Group18_20:461056  
 Mean   :10     Mean   :5.001   Wed  :567794   Mean   :12.97   Group9_11 :396514  
 3rd Qu.:10     3rd Qu.:6.000   Thurs:559180   3rd Qu.:18.00   Group12_14:353603  
 Max.   :10     Max.   :7.000   Fri  :561645   Max.   :23.00   Group21_23:244522  
                                Sat  :     0                   (Other)   :182119  
 Event_Time_Min    Event_Time                  Departure_Time               
 Min.   : 0.00   Min.   :2016-10-03 00:00:00   Min.   :2016-10-03 00:00:00  
 1st Qu.:14.00   1st Qu.:2016-10-04 08:36:14   1st Qu.:2016-10-04 08:36:20  
 Median :29.00   Median :2016-10-05 13:49:29   Median :2016-10-05 13:49:38  
 Mean   :29.43   Mean   :2016-10-05 13:29:21   Mean   :2016-10-05 13:29:28  
 3rd Qu.:44.00   3rd Qu.:2016-10-06 17:58:06   3rd Qu.:2016-10-06 17:58:13  
 Max.   :59.00   Max.   :2016-10-07 23:59:59   Max.   :2016-10-08 00:12:31  
                                                                            
   Dwell_Time       Dwell_Time2         Delta_Time         Latitude    
 Min.   :   0.00   Min.   :   0.000   Min.   :-5606.0   Min.   : 0.00  
 1st Qu.:   0.00   1st Qu.:   0.000   1st Qu.:   14.0   1st Qu.:38.86  
 Median :   0.00   Median :   0.000   Median :  157.0   Median :38.90  
 Mean   :  12.56   Mean   :   6.359   Mean   :  268.8   Mean   :38.91  
 3rd Qu.:   5.00   3rd Qu.:   4.000   3rd Qu.:  396.0   3rd Qu.:38.96  
 Max.   :6205.00   Max.   :6205.000   Max.   : 9426.0   Max.   :39.19  
                                                                       
   Longitude         Heading      Odometer_Distance  Odometer_Distance_Lag1
 Min.   :-77.45   Min.   :  0.0   Min.   :       0   Min.   :       0      
 1st Qu.:-77.07   1st Qu.: 89.0   1st Qu.:  177595   1st Qu.:  177326      
 Median :-77.02   Median :180.0   Median :  377510   Median :  376934      
 Mean   :-77.02   Mean   :176.9   Mean   :  426254   Mean   :  425713      
 3rd Qu.:-76.97   3rd Qu.:269.0   3rd Qu.:  623667   3rd Qu.:  622879      
 Max.   :  0.00   Max.   :360.0   Max.   :11108034   Max.   :10853226      
                                                     NA's   :6528          
 Odometer_Distance_Mi TravelDistance_Ft TravelDistance_Mi TravelDistance_Mi_Hvrs
 Min.   :   0.00      Min.   :      1   Min.   :  0.0     Min.   : 0.000        
 1st Qu.:  33.64      1st Qu.:    699   1st Qu.:  0.1     1st Qu.: 0.106        
 Median :  71.50      Median :   1044   Median :  0.2     Median : 0.142        
 Mean   :  80.73      Mean   :   1624   Mean   :  0.3     Mean   : 0.201        
 3rd Qu.: 118.12      3rd Qu.:   1518   3rd Qu.:  0.3     3rd Qu.: 0.193        
 Max.   :2103.79      Max.   :1323464   Max.   :250.7     Max.   :24.407        
                      NA's   :322734    NA's   :322734    NA's   :6528          
  TD_Mi_SS_q5       TD_Mi_SS_q95     TD_Mi_SSHG_q5    TD_Mi_SSHG_q95  
 Min.   :  0.000   Min.   :  0.000   Min.   :  0.00   Min.   :  0.00  
 1st Qu.:  0.086   1st Qu.:  0.262   1st Qu.:  0.09   1st Qu.:  0.25  
 Median :  0.104   Median :  0.326   Median :  0.11   Median :  0.31  
 Mean   :  0.164   Mean   :  0.488   Mean   :  0.18   Mean   :  0.47  
 3rd Qu.:  0.139   3rd Qu.:  0.436   3rd Qu.:  0.15   3rd Qu.:  0.42  
 Max.   :219.163   Max.   :246.949   Max.   :250.66   Max.   :250.66  
 NA's   :24757     NA's   :24757     NA's   :35629    NA's   :35629   
 TD_Mi_SS_Mean     TD_Mi_SS_Mean_F   TD_Mi_SSHG_Mean  TD_Mi_SSHG_Mean_F
 Min.   :  0.000   Min.   :  0.000   Min.   :  0.00   Min.   :  0.00   
 1st Qu.:  0.172   1st Qu.:  0.166   1st Qu.:  0.17   1st Qu.:  0.16   
 Median :  0.212   Median :  0.207   Median :  0.21   Median :  0.21   
 Mean   :  0.307   Mean   :  0.291   Mean   :  0.31   Mean   :  0.29   
 3rd Qu.:  0.267   3rd Qu.:  0.260   3rd Qu.:  0.27   3rd Qu.:  0.26   
 Max.   :219.163   Max.   :219.163   Max.   :250.66   Max.   :250.66   
 NA's   :24757     NA's   :27919     NA's   :35629    NA's   :44458    
  TD_Mi_SS_Med     TD_Mi_SS_Med_F    TD_Mi_SSHG_Med   TD_Mi_SSHG_Med_F
 Min.   :  0.000   Min.   :  0.000   Min.   :  0.00   Min.   :  0.00  
 1st Qu.:  0.146   1st Qu.:  0.146   1st Qu.:  0.14   1st Qu.:  0.14  
 Median :  0.196   Median :  0.196   Median :  0.20   Median :  0.20  
 Mean   :  0.288   Mean   :  0.282   Mean   :  0.29   Mean   :  0.28  
 3rd Qu.:  0.265   3rd Qu.:  0.265   3rd Qu.:  0.27   3rd Qu.:  0.27  
 Max.   :219.163   Max.   :219.163   Max.   :250.66   Max.   :250.66  
 NA's   :24757     NA's   :27919     NA's   :35629    NA's   :44458   
  TD_Mi_SS_Cnt    TD_Mi_SS_Cnt_F   TD_Mi_SSHG_Cnt   TD_Mi_SSHG_Cnt_F
 Min.   :   0.0   Min.   :   0.0   Min.   :  0.00   Min.   :  0.00  
 1st Qu.: 163.0   1st Qu.: 146.0   1st Qu.: 26.00   1st Qu.: 22.00  
 Median : 280.0   Median : 252.0   Median : 45.00   Median : 39.00  
 Mean   : 347.4   Mean   : 312.7   Mean   : 57.27   Mean   : 50.85  
 3rd Qu.: 456.0   3rd Qu.: 411.0   3rd Qu.: 75.00   3rd Qu.: 67.00  
 Max.   :1543.0   Max.   :1388.0   Max.   :663.00   Max.   :595.00  
                                                                    
 TravelTime_Sec     TT_Sec_SS_q5      TT_Sec_SS_q95      TT_Sec_SSHG_q5    
 Min.   :    1.0   Min.   :    1.00   Min.   :    1.00   Min.   :    1.00  
 1st Qu.:   25.0   1st Qu.:   15.00   1st Qu.:   48.00   1st Qu.:   16.00  
 Median :   39.0   Median :   22.00   Median :   80.05   Median :   23.40  
 Mean   :  104.9   Mean   :   61.26   Mean   :  183.28   Mean   :   67.33  
 3rd Qu.:   72.0   3rd Qu.:   34.00   3rd Qu.:  134.60   3rd Qu.:   36.70  
 Max.   :60750.0   Max.   :60750.00   Max.   :60750.00   Max.   :60750.00  
 NA's   :6641      NA's   :6531       NA's   :6531       NA's   :6535      
 TT_Sec_SSHG_q95    TT_Sec_SS_Mean     TT_Sec_SS_Mean_F   TT_Sec_SSHG_Mean  
 Min.   :    1.00   Min.   :    1.00   Min.   :    1.00   Min.   :    1.00  
 1st Qu.:   43.80   1st Qu.:   29.06   1st Qu.:   27.54   1st Qu.:   28.38  
 Median :   72.95   Median :   44.16   Median :   41.91   Median :   43.38  
 Mean   :  169.21   Mean   :  104.88   Mean   :   91.34   Mean   :  104.88  
 3rd Qu.:  123.65   3rd Qu.:   73.30   3rd Qu.:   69.25   3rd Qu.:   72.93  
 Max.   :60750.00   Max.   :60750.00   Max.   :60750.00   Max.   :60750.00  
 NA's   :6535       NA's   :6531       NA's   :10519      NA's   :6535      
 TT_Sec_SSHG_Mean_F TT_Sec_SS_Med      TT_Sec_SS_Med_F    TT_Sec_SSHG_Med   
 Min.   :    1.00   Min.   :    1.00   Min.   :    1.00   Min.   :    1.00  
 1st Qu.:   27.21   1st Qu.:   26.00   1st Qu.:   26.00   1st Qu.:   26.00  
 Median :   41.48   Median :   39.00   Median :   39.00   Median :   39.00  
 Mean   :   93.53   Mean   :   91.55   Mean   :   84.82   Mean   :   94.94  
 3rd Qu.:   70.12   3rd Qu.:   65.00   3rd Qu.:   65.00   3rd Qu.:   67.00  
 Max.   :60750.00   Max.   :60750.00   Max.   :60750.00   Max.   :60750.00  
 NA's   :12811      NA's   :6531       NA's   :10519      NA's   :6535      
 TT_Sec_SSHG_Med_F  TT_Sec_SS_Cnt    TT_Sec_SS_Cnt_F  TT_Sec_SSHG_Cnt 
 Min.   :    1.00   Min.   :   0.0   Min.   :   0.0   Min.   :  0.00  
 1st Qu.:   26.00   1st Qu.: 194.0   1st Qu.: 177.0   1st Qu.: 29.00  
 Median :   38.50   Median : 310.0   Median : 282.0   Median : 51.00  
 Mean   :   88.44   Mean   : 384.4   Mean   : 349.8   Mean   : 63.46  
 3rd Qu.:   66.50   3rd Qu.: 497.0   3rd Qu.: 452.0   3rd Qu.: 83.00  
 Max.   :60750.00   Max.   :1664.0   Max.   :1523.0   Max.   :691.00  
 NA's   :12811                                                        
 TT_Sec_SSHG_Cnt_F TravelTime_Hr     TT_Hr_SS_q5      TT_Hr_SS_q95   
 Min.   :  0.00    Min.   : 0.000   Min.   : 0.000   Min.   : 0.000  
 1st Qu.: 26.00    1st Qu.: 0.007   1st Qu.: 0.004   1st Qu.: 0.013  
 Median : 46.00    Median : 0.011   Median : 0.006   Median : 0.022  
 Mean   : 57.09    Mean   : 0.029   Mean   : 0.017   Mean   : 0.051  
 3rd Qu.: 74.00    3rd Qu.: 0.020   3rd Qu.: 0.009   3rd Qu.: 0.037  
 Max.   :634.00    Max.   :16.875   Max.   :16.875   Max.   :16.875  
                   NA's   :6641     NA's   :6531     NA's   :6531    
 TT_Hr_SSHG_q5    TT_Hr_SSHG_q95   TT_Hr_SS_Mean    TT_Hr_SS_Mean_F 
 Min.   : 0.000   Min.   : 0.000   Min.   : 0.000   Min.   : 0.000  
 1st Qu.: 0.004   1st Qu.: 0.012   1st Qu.: 0.008   1st Qu.: 0.008  
 Median : 0.006   Median : 0.020   Median : 0.012   Median : 0.012  
 Mean   : 0.019   Mean   : 0.047   Mean   : 0.029   Mean   : 0.025  
 3rd Qu.: 0.010   3rd Qu.: 0.034   3rd Qu.: 0.020   3rd Qu.: 0.019  
 Max.   :16.875   Max.   :16.875   Max.   :16.875   Max.   :16.875  
 NA's   :6535     NA's   :6535     NA's   :6531     NA's   :10532   
 TT_Hr_SSHG_Mean  TT_Hr_SSHG_Mean_F  TT_Hr_SS_Med    TT_Hr_SS_Med_F  
 Min.   : 0.000   Min.   : 0.000    Min.   : 0.000   Min.   : 0.000  
 1st Qu.: 0.008   1st Qu.: 0.008    1st Qu.: 0.007   1st Qu.: 0.007  
 Median : 0.012   Median : 0.012    Median : 0.011   Median : 0.011  
 Mean   : 0.029   Mean   : 0.026    Mean   : 0.025   Mean   : 0.024  
 3rd Qu.: 0.020   3rd Qu.: 0.019    3rd Qu.: 0.018   3rd Qu.: 0.018  
 Max.   :16.875   Max.   :16.875    Max.   :16.875   Max.   :16.875  
 NA's   :6535     NA's   :12895     NA's   :6531     NA's   :10532   
 TT_Hr_SSHG_Med   TT_Hr_SSHG_Med_F  TT_Hr_SS_Cnt    TT_Hr_SS_Cnt_F  
 Min.   : 0.000   Min.   : 0.000   Min.   :   0.0   Min.   :   0.0  
 1st Qu.: 0.007   1st Qu.: 0.007   1st Qu.: 194.0   1st Qu.: 176.0  
 Median : 0.011   Median : 0.011   Median : 310.0   Median : 282.0  
 Mean   : 0.026   Mean   : 0.025   Mean   : 384.4   Mean   : 349.6  
 3rd Qu.: 0.019   3rd Qu.: 0.018   3rd Qu.: 497.0   3rd Qu.: 452.0  
 Max.   :16.875   Max.   :16.875   Max.   :1664.0   Max.   :1523.0  
 NA's   :6535     NA's   :12895                                     
 TT_Hr_SSHG_Cnt   TT_Hr_SSHG_Cnt_F  SpeedAvg_Mph    
 Min.   :  0.00   Min.   :  0.00   Min.   :    0.0  
 1st Qu.: 29.00   1st Qu.: 26.00   1st Qu.:   10.1  
 Median : 51.00   Median : 46.00   Median :   16.7  
 Mean   : 63.46   Mean   : 57.05   Mean   :   26.5  
 3rd Qu.: 83.00   3rd Qu.: 74.00   3rd Qu.:   31.2  
 Max.   :691.00   Max.   :634.00   Max.   :22924.1  
                                   NA's   :322762   

Investigation of TravelDistance_Mi.

View(TravDistMi_Pctiles): 99% of TravelDistance_Mi are about 1 mile or less…but some weird TravelDistance_Mi values (e.g., 584 miles traveled) exist.

Investigation of TravelDistance_Mi.

Why are some TravelDistance_Mi “NA”? It looks like partially because the records are the first trip of the day (for that bus), so I purposefully set the distance to “NA”. Another reason is due to the odometer recording a value less than the previous odometer recording. In most cases, I have no explanation for this - though I have observed about 67% of all instances where TravelDistance_Mi is NA (other than because it’s the first record of the day) are instances where DirChange2 is “Change”. This is weird and should be asked to WMATA.

Investigation of TravelDistance_Mi.

These records are NA becuase the current record odometer is less than the previous record odometer. Theoretically, this should NOT happen. Me: it appears that about 67% of all instances where TravelDistance_Mi is NA (other than because it’s th first record of the day) are instances where DirChange2 is “Change”. This is weird and should be asked to WMATA.

prop.table(as.table(as.matrix(TestTable_Spread)
                   ),
           1
          )
           False      True
Change 0.8298069 0.1701931
Same   0.8884570 0.1115430
prop.table(as.table(as.matrix(TestTable_Spread)
                   ),
           2
          )
            False       True
Change 0.02020231 0.03258635
Same   0.97979769 0.96741365

Investigation of TravelDistance_Mi.

Let’s look at just the TravelDistance_Mi values that are NOT “NA”.

str(TravelDistance_Mi_NoNA)
'data.frame':   2486795 obs. of  89 variables:
 $ RowNum_OG             : int  3 4 5 6 7 9 10 11 12 13 ...
 $ group                 : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ StartStop_ID          : chr  "5004572--5004573" "5004573--5002210" "5002210--5002209" "5002209--5000070" ...
 $ BusDay_EventNum       : int  2 3 4 5 6 7 8 9 10 11 ...
 $ Bus_ID                : int  11 11 11 11 11 11 11 11 11 11 ...
 $ Route                 : chr  "S80" "S80" "S80" "S80" ...
 $ RouteAlt              : Factor w/ 14 levels "1","10","11",..: 1 1 1 1 1 6 6 6 6 6 ...
 $ DirChange2            : Factor w/ 2 levels "Change","Same": 2 2 2 2 2 1 2 2 2 2 ...
 $ Route_Direction       : Factor w/ 12 levels "","ANTICLKW",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ Stop_Sequence         : int  6 3 2 8 1 2 3 4 2 6 ...
 $ Start_ID              : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ Start_Desc            : chr  "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" "BEULAH ST + CHARLES ARRINGTON DR" ...
 $ StopID_Clean          : chr  "5004573" "5002210" "5002209" "5000070" ...
 $ StopID_Indicator      : Factor w/ 2 levels "ID_Bad","ID_OK": 2 2 2 2 2 2 2 2 2 2 ...
 $ Stop_Desc             : chr  "WALKER LN + #6363" "WALKER LN + BEULAH ST" "BEULAH ST + CHARLES ARRINGTON DR" "FRANCONIA-SPRGFLD STA. + BUS BAY D" ...
 $ Event_Type            : int  4 4 4 3 3 4 4 4 4 4 ...
 $ Event_Description     : Factor w/ 3 levels "Serviced Stop                                     ",..: 3 3 3 1 1 3 3 3 3 3 ...
 $ Event_Time_Yr         : int  2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
 $ Event_Time_Mth        : int  10 10 10 10 10 10 10 10 10 10 ...
 $ Event_Time_Date       : int  3 3 3 3 3 3 3 3 3 3 ...
 $ Event_Time_Day        : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
 $ Event_Time_Hr         : int  6 6 6 6 6 6 6 6 6 6 ...
 $ Event_Time_HrGroup    : Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 3 3 3 3 3 3 3 3 3 3 ...
 $ Event_Time_Min        : int  9 10 10 13 14 21 21 23 23 26 ...
 $ Event_Time            : POSIXct, format: "2016-10-03 06:09:47" "2016-10-03 06:10:24" ...
 $ Departure_Time        : POSIXct, format: "2016-10-03 06:09:47" "2016-10-03 06:10:24" ...
 $ Dwell_Time            : int  0 0 0 0 104 0 0 0 0 0 ...
 $ Dwell_Time2           : num  0 0 0 0 104 0 0 0 0 0 ...
 $ Delta_Time            : int  24 165 25 73 719 74 76 63 69 165 ...
 $ Latitude              : num  38.8 38.8 38.8 38.8 38.8 ...
 $ Longitude             : num  -77.2 -77.2 -77.2 -77.2 -77.2 ...
 $ Heading               : int  97 276 15 119 100 274 104 241 274 1 ...
 $ Odometer_Distance     : int  45139 46418 50115 51074 51303 55633 56163 56285 57262 58363 ...
 $ Odometer_Distance_Lag1: int  43543 45139 46418 50115 51074 51303 55633 56163 56285 57262 ...
 $ Odometer_Distance_Mi  : num  8.55 8.79 9.49 9.67 9.72 ...
 $ TravelDistance_Ft     : int  1596 1279 3697 959 229 4330 530 122 977 1101 ...
 $ TravelDistance_Mi     : num  0.3023 0.2422 0.7002 0.1816 0.0434 ...
 $ TravelDistance_Mi_Hvrs: num  0.15 0.105 0.165 0.832 0.068 ...
 $ TD_Mi_SS_q5           : num  0.025246 0.242235 0.732434 0.079432 0.000436 ...
 $ TD_Mi_SS_q95          : num  0.626 0.242 1.008 0.176 10.435 ...
 $ TD_Mi_SSHG_q5         : num  0.09956 0.24223 0.70019 0.18163 0.00269 ...
 $ TD_Mi_SSHG_q95        : num  0.627 0.242 0.7 0.182 0.497 ...
 $ TD_Mi_SS_Mean         : num  0.437 0.242 0.908 0.128 1.166 ...
 $ TD_Mi_SS_Mean_F       : num  0.457 0.242 0.977 NaN 0.226 ...
 $ TD_Mi_SSHG_Mean       : num  0.442 0.242 0.7 0.182 0.232 ...
 $ TD_Mi_SSHG_Mean_F     : num  0.491 0.242 0.7 0.182 0.228 ...
 $ TD_Mi_SS_Med          : num  0.5116 0.2422 0.9616 0.1278 0.0426 ...
 $ TD_Mi_SS_Med_F        : num  0.5116 0.2422 1.0081 NA 0.0426 ...
 $ TD_Mi_SSHG_Med        : num  0.512 0.242 0.7 0.182 0.108 ...
 $ TD_Mi_SSHG_Med_F      : num  0.512 0.242 0.7 0.182 0.108 ...
 $ TD_Mi_SS_Cnt          : int  14 1 4 2 87 22 118 91 11 2 ...
 $ TD_Mi_SS_Cnt_F        : int  12 1 3 0 77 18 106 81 9 0 ...
 $ TD_Mi_SSHG_Cnt        : int  7 1 1 1 23 6 29 28 3 1 ...
 $ TD_Mi_SSHG_Cnt_F      : int  5 1 1 1 19 4 25 24 1 1 ...
 $ TravelTime_Sec        : num  180 37 25 190 29 288 52 76 8 189 ...
 $ TT_Sec_SS_q5          : num  11.9 37 30.5 172.9 10 ...
 $ TT_Sec_SS_q95         : num  346.3 37 75.8 189.1 1737.2 ...
 $ TT_Sec_SSHG_q5        : num  59.6 37 25 190 11.6 236 51.5 55 8.8 189 ...
 $ TT_Sec_SSHG_q95       : num  276 37 25 190 675 ...
 $ TT_Sec_SS_Mean        : num  215.8 37 58.2 181 585.3 ...
 $ TT_Sec_SS_Mean_F      : num  218.9 37 65.5 NaN 249.3 ...
 $ TT_Sec_SSHG_Mean      : num  202 37 25 190 257 ...
 $ TT_Sec_SSHG_Mean_F    : num  226 37 25 190 244 ...
 $ TT_Sec_SS_Med         : num  223.5 37 65.5 181 33 ...
 $ TT_Sec_SS_Med_F       : num  223.5 37 65.5 NA 32 ...
 $ TT_Sec_SSHG_Med       : num  219 37 25 190 134 286 60 65 16 189 ...
 $ TT_Sec_SSHG_Med_F     : num  219 37 25 190 134 286 60 65 16 189 ...
 $ TT_Sec_SS_Cnt         : int  14 1 4 2 173 22 141 141 11 2 ...
 $ TT_Sec_SS_Cnt_F       : int  12 1 2 0 156 18 127 128 9 0 ...
 $ TT_Sec_SSHG_Cnt       : int  7 1 1 1 35 6 36 35 3 1 ...
 $ TT_Sec_SSHG_Cnt_F     : int  5 1 1 1 31 4 32 32 1 1 ...
 $ TravelTime_Hr         : num  0.05 0.01028 0.00694 0.05278 0.00806 ...
 $ TT_Hr_SS_q5           : num  0.00331 0.01028 0.00849 0.04803 0.00278 ...
 $ TT_Hr_SS_q95          : num  0.0962 0.0103 0.0211 0.0525 0.4826 ...
 $ TT_Hr_SSHG_q5         : num  0.01656 0.01028 0.00694 0.05278 0.00322 ...
 $ TT_Hr_SSHG_q95        : num  0.07653 0.01028 0.00694 0.05278 0.18739 ...
 $ TT_Hr_SS_Mean         : num  0.0599 0.0103 0.0162 0.0503 0.1626 ...
 $ TT_Hr_SS_Mean_F       : num  0.0608 0.0103 0.0182 NaN 0.0692 ...
 $ TT_Hr_SSHG_Mean       : num  0.05615 0.01028 0.00694 0.05278 0.0715 ...
 $ TT_Hr_SSHG_Mean_F     : num  0.06278 0.01028 0.00694 0.05278 0.0677 ...
 $ TT_Hr_SS_Med          : num  0.06208 0.01028 0.01819 0.05028 0.00917 ...
 $ TT_Hr_SS_Med_F        : num  0.06208 0.01028 0.01819 NA 0.00889 ...
 $ TT_Hr_SSHG_Med        : num  0.06083 0.01028 0.00694 0.05278 0.03722 ...
 $ TT_Hr_SSHG_Med_F      : num  0.06083 0.01028 0.00694 0.05278 0.03722 ...
 $ TT_Hr_SS_Cnt          : int  14 1 4 2 173 22 141 141 11 2 ...
 $ TT_Hr_SS_Cnt_F        : int  12 1 2 0 156 18 127 128 9 0 ...
 $ TT_Hr_SSHG_Cnt        : int  7 1 1 1 35 6 36 35 3 1 ...
 $ TT_Hr_SSHG_Cnt_F      : int  5 1 1 1 31 4 32 28 1 1 ...
 $ SpeedAvg_Mph          : num  6.05 23.57 100.83 3.44 5.38 ...
summary(TravelDistance_Mi_NoNA)
   RowNum_OG       group      StartStop_ID       BusDay_EventNum      Bus_ID    
 Min.   :      3   1:496190   Length:2486795     Min.   :   2.0   Min.   :  11  
 1st Qu.: 786568   2:497932   Class :character   1st Qu.: 115.0   1st Qu.:2923  
 Median :1590497   3:501611   Mode  :character   Median : 251.0   Median :6202  
 Mean   :1578192   4:495069                      Mean   : 293.2   Mean   :5431  
 3rd Qu.:2351264   5:495993                      3rd Qu.: 431.0   3rd Qu.:7113  
 Max.   :3119443                                 Max.   :1344.0   Max.   :8105  
                                                                                
    Route              RouteAlt       DirChange2      Route_Direction  
 Length:2486795     2      :994645   Change:  50239   SOUTH   :667198  
 Class :character   1      :943279   Same  :2436556   NORTH   :662471  
 Mode  :character   3      :229032                    WEST    :565616  
                    4      :117090                    EAST    :543386  
                    5      : 67811                    LOOP    : 33484  
                    6      : 51391                    CLOCKWIS:  7012  
                    (Other): 83547                    (Other) :  7628  
 Stop_Sequence      Start_ID          Start_Desc        StopID_Clean      
 Min.   :  1.00   Length:2486795     Length:2486795     Length:2486795    
 1st Qu.: 12.00   Class :character   Class :character   Class :character  
 Median : 24.00   Mode  :character   Mode  :character   Mode  :character  
 Mean   : 27.13                                                           
 3rd Qu.: 39.00                                                           
 Max.   :104.00                                                           
                                                                          
 StopID_Indicator  Stop_Desc           Event_Type   
 ID_Bad:  14271   Length:2486795     Min.   :3.000  
 ID_OK :2472524   Class :character   1st Qu.:3.000  
                  Mode  :character   Median :4.000  
                                     Mean   :3.626  
                                     3rd Qu.:4.000  
                                     Max.   :5.000  
                                                    
                                          Event_Description   Event_Time_Yr 
 Serviced Stop                                     : 930934   Min.   :2016  
 Unknown Stop                                      :   1794   1st Qu.:2016  
 UnServiced Stop                                   :1554067   Median :2016  
                                                              Mean   :2016  
                                                              3rd Qu.:2016  
                                                              Max.   :2016  
                                                                            
 Event_Time_Mth Event_Time_Date Event_Time_Day Event_Time_Hr    Event_Time_HrGroup
 Min.   :10     Min.   :3.000   Sun  :     0   Min.   : 0.00   Group6_8  :538348  
 1st Qu.:10     1st Qu.:4.000   Mon  :496190   1st Qu.: 8.00   Group15_17:497156  
 Median :10     Median :5.000   Tues :497932   Median :13.00   Group18_20:408957  
 Mean   :10     Mean   :4.999   Wed  :501611   Mean   :12.99   Group9_11 :351804  
 3rd Qu.:10     3rd Qu.:6.000   Thurs:495069   3rd Qu.:18.00   Group12_14:314050  
 Max.   :10     Max.   :7.000   Fri  :495993   Max.   :23.00   Group21_23:217259  
                                Sat  :     0                   (Other)   :159221  
 Event_Time_Min    Event_Time                  Departure_Time               
 Min.   : 0.00   Min.   :2016-10-03 00:00:09   Min.   :2016-10-03 00:00:09  
 1st Qu.:14.00   1st Qu.:2016-10-04 08:35:52   1st Qu.:2016-10-04 08:35:59  
 Median :29.00   Median :2016-10-05 13:46:00   Median :2016-10-05 13:46:06  
 Mean   :29.43   Mean   :2016-10-05 13:27:43   Mean   :2016-10-05 13:27:49  
 3rd Qu.:44.00   3rd Qu.:2016-10-06 17:57:32   3rd Qu.:2016-10-06 17:57:39  
 Max.   :59.00   Max.   :2016-10-07 23:59:59   Max.   :2016-10-08 00:12:31  
                                                                            
   Dwell_Time       Dwell_Time2         Delta_Time         Latitude    
 Min.   :   0.00   Min.   :   0.000   Min.   :-5606.0   Min.   : 0.00  
 1st Qu.:   0.00   1st Qu.:   0.000   1st Qu.:   16.0   1st Qu.:38.86  
 Median :   0.00   Median :   0.000   Median :  160.0   Median :38.90  
 Mean   :  11.86   Mean   :   5.994   Mean   :  274.1   Mean   :38.91  
 3rd Qu.:   4.00   3rd Qu.:   4.000   3rd Qu.:  402.0   3rd Qu.:38.96  
 Max.   :6205.00   Max.   :6205.000   Max.   : 9426.0   Max.   :39.19  
                                                                       
   Longitude         Heading      Odometer_Distance  Odometer_Distance_Lag1
 Min.   :-77.45   Min.   :  0.0   Min.   :       1   Min.   :       0      
 1st Qu.:-77.07   1st Qu.: 89.0   1st Qu.:  200268   1st Qu.:  198635      
 Median :-77.01   Median :180.0   Median :  394700   Median :  393026      
 Mean   :-77.02   Mean   :176.7   Mean   :  443225   Mean   :  441601      
 3rd Qu.:-76.97   3rd Qu.:269.0   3rd Qu.:  633936   3rd Qu.:  632313      
 Max.   :  0.00   Max.   :360.0   Max.   :11108034   Max.   :10853226      
                                                                           
 Odometer_Distance_Mi TravelDistance_Ft TravelDistance_Mi   TravelDistance_Mi_Hvrs
 Min.   :   0.0002    Min.   :      1   Min.   :  0.00019   Min.   : 0.0000       
 1st Qu.:  37.9295    1st Qu.:    699   1st Qu.:  0.13239   1st Qu.: 0.1034       
 Median :  74.7538    Median :   1044   Median :  0.19773   Median : 0.1378       
 Mean   :  83.9442    Mean   :   1624   Mean   :  0.30760   Mean   : 0.1918       
 3rd Qu.: 120.0635    3rd Qu.:   1518   3rd Qu.:  0.28750   3rd Qu.: 0.1828       
 Max.   :2103.7943    Max.   :1323464   Max.   :250.65606   Max.   :24.1507       
                                                                                  
  TD_Mi_SS_q5         TD_Mi_SS_q95       TD_Mi_SSHG_q5       TD_Mi_SSHG_q95     
 Min.   :  0.00019   Min.   :  0.00019   Min.   :  0.00019   Min.   :  0.00019  
 1st Qu.:  0.08848   1st Qu.:  0.25878   1st Qu.:  0.09167   1st Qu.:  0.24754  
 Median :  0.10608   Median :  0.32239   Median :  0.11395   Median :  0.31174  
 Mean   :  0.16872   Mean   :  0.47949   Mean   :  0.18528   Mean   :  0.46625  
 3rd Qu.:  0.13977   3rd Qu.:  0.42822   3rd Qu.:  0.15093   3rd Qu.:  0.41899  
 Max.   :219.16288   Max.   :246.94938   Max.   :250.65606   Max.   :250.65606  
                                                                                
 TD_Mi_SS_Mean       TD_Mi_SS_Mean_F    TD_Mi_SSHG_Mean     TD_Mi_SSHG_Mean_F
 Min.   :  0.00019   Min.   :  0.0002   Min.   :  0.00019   Min.   :  0.000  
 1st Qu.:  0.17129   1st Qu.:  0.1663   1st Qu.:  0.16760   1st Qu.:  0.163  
 Median :  0.21082   Median :  0.2058   Median :  0.20965   Median :  0.206  
 Mean   :  0.30760   Mean   :  0.2916   Mean   :  0.30760   Mean   :  0.294  
 3rd Qu.:  0.26422   3rd Qu.:  0.2582   3rd Qu.:  0.26616   3rd Qu.:  0.262  
 Max.   :219.16288   Max.   :219.1629   Max.   :250.65606   Max.   :250.656  
                     NA's   :2678                           NA's   :4904     
  TD_Mi_SS_Med       TD_Mi_SS_Med_F     TD_Mi_SSHG_Med      TD_Mi_SSHG_Med_F 
 Min.   :  0.00019   Min.   :  0.0002   Min.   :  0.00019   Min.   :  0.000  
 1st Qu.:  0.14602   1st Qu.:  0.1458   1st Qu.:  0.14403   1st Qu.:  0.144  
 Median :  0.19470   Median :  0.1947   Median :  0.19527   Median :  0.195  
 Mean   :  0.28931   Mean   :  0.2827   Mean   :  0.29152   Mean   :  0.285  
 3rd Qu.:  0.26326   3rd Qu.:  0.2633   3rd Qu.:  0.26657   3rd Qu.:  0.266  
 Max.   :219.16288   Max.   :219.1629   Max.   :250.65606   Max.   :250.656  
                     NA's   :2678                           NA's   :4904     
  TD_Mi_SS_Cnt    TD_Mi_SS_Cnt_F   TD_Mi_SSHG_Cnt   TD_Mi_SSHG_Cnt_F
 Min.   :   1.0   Min.   :   0.0   Min.   :  1.00   Min.   :  0.00  
 1st Qu.: 178.0   1st Qu.: 160.0   1st Qu.: 28.00   1st Qu.: 24.00  
 Median : 295.0   Median : 266.0   Median : 48.00   Median : 42.00  
 Mean   : 363.3   Mean   : 327.1   Mean   : 60.01   Mean   : 53.31  
 3rd Qu.: 476.0   3rd Qu.: 428.0   3rd Qu.: 78.00   3rd Qu.: 70.00  
 Max.   :1543.0   Max.   :1388.0   Max.   :663.00   Max.   :595.00  
                                                                    
 TravelTime_Sec   TT_Sec_SS_q5      TT_Sec_SS_q95      TT_Sec_SSHG_q5    
 Min.   :    1   Min.   :    1.00   Min.   :    1.00   Min.   :    1.00  
 1st Qu.:   24   1st Qu.:   15.00   1st Qu.:   47.00   1st Qu.:   15.20  
 Median :   38   Median :   21.00   Median :   77.75   Median :   22.50  
 Mean   :  100   Mean   :   57.38   Mean   :  176.22   Mean   :   62.94  
 3rd Qu.:   70   3rd Qu.:   32.00   3rd Qu.:  129.65   3rd Qu.:   34.80  
 Max.   :54551   Max.   :54551.00   Max.   :54551.00   Max.   :54551.00  
 NA's   :28                                                              
 TT_Sec_SSHG_q95    TT_Sec_SS_Mean     TT_Sec_SS_Mean_F   TT_Sec_SSHG_Mean  
 Min.   :    1.00   Min.   :    1.00   Min.   :    1.00   Min.   :    1.00  
 1st Qu.:   42.70   1st Qu.:   28.20   1st Qu.:   26.62   1st Qu.:   27.51  
 Median :   70.55   Median :   42.61   Median :   40.46   Median :   41.76  
 Mean   :  161.25   Mean   :   99.62   Mean   :   86.96   Mean   :   99.55  
 3rd Qu.:  119.60   3rd Qu.:   69.71   3rd Qu.:   66.44   3rd Qu.:   70.02  
 Max.   :54551.00   Max.   :54551.00   Max.   :54551.00   Max.   :54551.00  
                                       NA's   :2603                         
 TT_Sec_SSHG_Mean_F TT_Sec_SS_Med      TT_Sec_SS_Med_F    TT_Sec_SSHG_Med   
 Min.   :    1.00   Min.   :    1.00   Min.   :    1.00   Min.   :    1.00  
 1st Qu.:   26.34   1st Qu.:   25.00   1st Qu.:   25.00   1st Qu.:   25.00  
 Median :   39.96   Median :   37.00   Median :   37.00   Median :   37.00  
 Mean   :   88.81   Mean   :   86.88   Mean   :   80.62   Mean   :   90.07  
 3rd Qu.:   67.22   3rd Qu.:   62.00   3rd Qu.:   62.00   3rd Qu.:   64.00  
 Max.   :54551.00   Max.   :54551.00   Max.   :54551.00   Max.   :54551.00  
 NA's   :3772                          NA's   :2603                         
 TT_Sec_SSHG_Med_F  TT_Sec_SS_Cnt    TT_Sec_SS_Cnt_F  TT_Sec_SSHG_Cnt
 Min.   :    1.00   Min.   :   1.0   Min.   :   0.0   Min.   :  1.0  
 1st Qu.:   25.00   1st Qu.: 200.0   1st Qu.: 183.0   1st Qu.: 30.0  
 Median :   37.00   Median : 321.0   Median : 292.0   Median : 52.0  
 Mean   :   83.87   Mean   : 392.4   Mean   : 357.2   Mean   : 64.7  
 3rd Qu.:   64.00   3rd Qu.: 509.0   3rd Qu.: 464.0   3rd Qu.: 84.0  
 Max.   :54551.00   Max.   :1664.0   Max.   :1523.0   Max.   :691.0  
 NA's   :3772                                                        
 TT_Sec_SSHG_Cnt_F TravelTime_Hr        TT_Hr_SS_q5         TT_Hr_SS_q95      
 Min.   :  0.00    Min.   : 0.000278   Min.   : 0.000278   Min.   : 0.000278  
 1st Qu.: 27.00    1st Qu.: 0.006667   1st Qu.: 0.004167   1st Qu.: 0.013056  
 Median : 47.00    Median : 0.010556   Median : 0.005833   Median : 0.021597  
 Mean   : 58.23    Mean   : 0.027782   Mean   : 0.015938   Mean   : 0.048950  
 3rd Qu.: 76.00    3rd Qu.: 0.019444   3rd Qu.: 0.008889   3rd Qu.: 0.036014  
 Max.   :634.00    Max.   :15.153056   Max.   :15.153056   Max.   :15.153056  
                   NA's   :28                                                 
 TT_Hr_SSHG_q5       TT_Hr_SSHG_q95      TT_Hr_SS_Mean       TT_Hr_SS_Mean_F  
 Min.   : 0.000278   Min.   : 0.000278   Min.   : 0.000278   Min.   : 0.0003  
 1st Qu.: 0.004222   1st Qu.: 0.011861   1st Qu.: 0.007832   1st Qu.: 0.0074  
 Median : 0.006250   Median : 0.019597   Median : 0.011836   Median : 0.0112  
 Mean   : 0.017485   Mean   : 0.044792   Mean   : 0.027673   Mean   : 0.0242  
 3rd Qu.: 0.009667   3rd Qu.: 0.033222   3rd Qu.: 0.019363   3rd Qu.: 0.0185  
 Max.   :15.153056   Max.   :15.153056   Max.   :15.153056   Max.   :15.1531  
                                                             NA's   :2612     
 TT_Hr_SSHG_Mean     TT_Hr_SSHG_Mean_F  TT_Hr_SS_Med       TT_Hr_SS_Med_F   
 Min.   : 0.000278   Min.   : 0.000    Min.   : 0.000278   Min.   : 0.0003  
 1st Qu.: 0.007643   1st Qu.: 0.007    1st Qu.: 0.006944   1st Qu.: 0.0069  
 Median : 0.011600   Median : 0.011    Median : 0.010278   Median : 0.0103  
 Mean   : 0.027654   Mean   : 0.025    Mean   : 0.024132   Mean   : 0.0224  
 3rd Qu.: 0.019450   3rd Qu.: 0.019    3rd Qu.: 0.017222   3rd Qu.: 0.0172  
 Max.   :15.153056   Max.   :15.153    Max.   :15.153056   Max.   :15.1531  
                     NA's   :3842                          NA's   :2612     
 TT_Hr_SSHG_Med      TT_Hr_SSHG_Med_F  TT_Hr_SS_Cnt    TT_Hr_SS_Cnt_F
 Min.   : 0.000278   Min.   : 0.000   Min.   :   1.0   Min.   :   0  
 1st Qu.: 0.006944   1st Qu.: 0.007   1st Qu.: 200.0   1st Qu.: 183  
 Median : 0.010278   Median : 0.010   Median : 321.0   Median : 292  
 Mean   : 0.025019   Mean   : 0.023   Mean   : 392.4   Mean   : 357  
 3rd Qu.: 0.017778   3rd Qu.: 0.018   3rd Qu.: 509.0   3rd Qu.: 464  
 Max.   :15.153056   Max.   :15.153   Max.   :1664.0   Max.   :1523  
                     NA's   :3842                                    
 TT_Hr_SSHG_Cnt  TT_Hr_SSHG_Cnt_F  SpeedAvg_Mph     
 Min.   :  1.0   Min.   :  0.00   Min.   :    0.00  
 1st Qu.: 30.0   1st Qu.: 27.00   1st Qu.:   10.10  
 Median : 52.0   Median : 47.00   Median :   16.68  
 Mean   : 64.7   Mean   : 58.19   Mean   :   26.54  
 3rd Qu.: 84.0   3rd Qu.: 76.00   3rd Qu.:   31.17  
 Max.   :691.0   Max.   :634.00   Max.   :22924.09  
                                  NA's   :28        

Investigation of TravelDistance_Mi.

Let’s plot just the TravelDistance_Mi values that are NOT “NA”.

Investigation of TravelDistance_Mi.

Looking at the extremely large TravelDistance_Mi values. Some (aprox 27%) of TravelDistance_Mi values > 1 mile are when the DirChange2 changes…but what about the other ~73%?

Investigation of TravelDistance_Mi.

Any relation with DirChange2? Doesn’t look as if this is so.

prop.table(as.table(as.matrix(ExtremeTravDist_Spread)
                   ),
           1
          )
            False       True
Change 0.76966102 0.23033898
Same   0.98944289 0.01055711
prop.table(as.table(as.matrix(ExtremeTravDist_Spread)
                   ),
           2
          )
            False       True
Change 0.01578567 0.31028288
Same   0.98421433 0.68971712

Investigation of TravelDistance_Mi.

Looking at specific buses and StartStop_ID.

Investigation of TravelDistance_Mi & TravelDistance_Mi_New.

If TravelDisntace_Mi is below the 5th percentile for that StartStop_ID, or if TravelDisntace_Mi is above the 95th percentile for that StartStop_ID, or if TravelDistance_Mi is NA (when the BusDay_EventNum !=1), consider this an outlier. In this case, replace the value with the mean for that StartStop_ID and HourGroup (TD_Mi_SSHG_Mean_F), or if there are not enough values at the HourGroup level, replace it with the mean for that StartStop_ID.

# View(tail(AllDays_NewOrder, 500))
AllDays_NewTravelDist <- 
  mutate(AllDays_NewOrder,
         TravelDistance_Mi_New = ifelse(!is.na(TravelDistance_Mi) & 
                                          (TravelDistance_Mi < TD_Mi_SSHG_q5 |
                                             TravelDistance_Mi > TD_Mi_SSHG_q95
                                          ) &
                                          TD_Mi_SSHG_Cnt_F >= 20,
                                        TD_Mi_SSHG_Mean_F,
                                 ifelse(!is.na(TravelDistance_Mi) & 
                                          (TravelDistance_Mi < TD_Mi_SSHG_q5 |
                                             TravelDistance_Mi > TD_Mi_SSHG_q95
                                          ) &
                                          TD_Mi_SSHG_Cnt_F < 20 &
                                          TD_Mi_SS_Cnt_F >= 20,
                                        TD_Mi_SS_Mean_F,
                                 ifelse(!is.na(TravelDistance_Mi) & 
                                          (TravelDistance_Mi < TD_Mi_SSHG_q5 |
                                             TravelDistance_Mi > TD_Mi_SSHG_q95
                                          ) &
                                          TD_Mi_SS_Cnt_F < 20 &
                                          TD_Mi_SS_Cnt >= 20,
                                        TD_Mi_SS_Mean,
                                 ifelse(is.na(TravelDistance_Mi) &
                                          BusDay_EventNum != 1 &
                                          TravelDistance_Mi_Hvrs != 0,
                                        TravelDistance_Mi_Hvrs,
                                 ifelse(is.na(TravelDistance_Mi) &
                                          BusDay_EventNum != 1 &
                                          TravelDistance_Mi_Hvrs == 0,
                                        TD_Mi_SS_Mean,
                                        TravelDistance_Mi
                                       ))))),
         TravelDistance_Mi_New_Label = 
           factor(ifelse(!is.na(TravelDistance_Mi) &
                           (TravelDistance_Mi < TD_Mi_SSHG_q5 |
                              TravelDistance_Mi > TD_Mi_SSHG_q95
                           ) &
                           TD_Mi_SSHG_Cnt_F >= 20,
                         "TD_Mi_SSHG_Mean_F",
                  ifelse(!is.na(TravelDistance_Mi) &
                           (TravelDistance_Mi < TD_Mi_SSHG_q5 |
                              TravelDistance_Mi > TD_Mi_SSHG_q95
                           ) &
                           TD_Mi_SSHG_Cnt_F < 20 &
                           TD_Mi_SS_Cnt_F >= 20,
                         "TD_Mi_SS_Mean_F",
                  ifelse(!is.na(TravelDistance_Mi) &
                           (TravelDistance_Mi < TD_Mi_SSHG_q5 |
                              TravelDistance_Mi > TD_Mi_SSHG_q95
                           ) &
                           TD_Mi_SS_Cnt_F < 20 &
                           TD_Mi_SS_Cnt >= 20,
                         "TD_Mi_SS_Mean",
                  ifelse(is.na(TravelDistance_Mi) &
                           BusDay_EventNum != 1 &
                           TravelDistance_Mi_Hvrs != 0,
                         "TravelDistance_Mi_Hvrs",
                  ifelse(is.na(TravelDistance_Mi) &
                           BusDay_EventNum != 1 &
                           TravelDistance_Mi_Hvrs == 0,
                         TD_Mi_SS_Mean,
                         "TravelDistance_Mi"
                        )))))
                 )
        )
str(AllDays_NewTravelDist)
'data.frame':   2809529 obs. of  91 variables:
 $ RowNum_OG                  : int  1 3 4 5 6 7 9 10 11 12 ...
 $ group                      : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ StartStop_ID               : chr  "NULL--5004572" "5004572--5004573" "5004573--5002210" "5002210--5002209" ...
 $ BusDay_EventNum            : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Bus_ID                     : int  11 11 11 11 11 11 11 11 11 11 ...
 $ Route                      : chr  "S80" "S80" "S80" "S80" ...
 $ RouteAlt                   : Factor w/ 14 levels "1","10","11",..: 1 1 1 1 1 1 6 6 6 6 ...
 $ DirChange2                 : Factor w/ 2 levels "Change","Same": 1 2 2 2 2 2 1 2 2 2 ...
 $ Route_Direction            : Factor w/ 12 levels "","ANTICLKW",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ Stop_Sequence              : int  7 6 3 2 8 1 2 3 4 2 ...
 $ Start_ID                   : chr  NA "5004572" "5004573" "5002210" ...
 $ Start_Desc                 : chr  NA "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" ...
 $ StopID_Clean               : chr  "5004572" "5004573" "5002210" "5002209" ...
 $ StopID_Indicator           : Factor w/ 2 levels "ID_Bad","ID_OK": 2 2 2 2 2 2 2 2 2 2 ...
 $ Stop_Desc                  : chr  "BEULAH ST + CHARLES ARRINGTON DR" "WALKER LN + #6363" "WALKER LN + BEULAH ST" "BEULAH ST + CHARLES ARRINGTON DR" ...
 $ Event_Type                 : int  4 4 4 4 3 3 4 4 4 4 ...
 $ Event_Description          : Factor w/ 3 levels "Serviced Stop                                     ",..: 3 3 3 3 1 1 3 3 3 3 ...
 $ Event_Time_Yr              : int  2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
 $ Event_Time_Mth             : int  10 10 10 10 10 10 10 10 10 10 ...
 $ Event_Time_Date            : int  3 3 3 3 3 3 3 3 3 3 ...
 $ Event_Time_Day             : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
 $ Event_Time_Hr              : int  6 6 6 6 6 6 6 6 6 6 ...
 $ Event_Time_HrGroup         : Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 3 3 3 3 3 3 3 3 3 3 ...
 $ Event_Time_Min             : int  6 9 10 10 13 14 21 21 23 23 ...
 $ Event_Time                 : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Departure_Time             : POSIXct, format: "2016-10-03 06:06:47" "2016-10-03 06:09:47" ...
 $ Dwell_Time                 : int  0 0 0 0 0 104 0 0 0 0 ...
 $ Dwell_Time2                : num  0 0 0 0 0 104 0 0 0 0 ...
 $ Delta_Time                 : int  -177 24 165 25 73 719 74 76 63 69 ...
 $ Latitude                   : num  38.8 38.8 38.8 38.8 38.8 ...
 $ Longitude                  : num  -77.2 -77.2 -77.2 -77.2 -77.2 ...
 $ Heading                    : int  199 97 276 15 119 100 274 104 241 274 ...
 $ Odometer_Distance          : int  43543 45139 46418 50115 51074 51303 55633 56163 56285 57262 ...
 $ Odometer_Distance_Lag1     : int  NA 43543 45139 46418 50115 51074 51303 55633 56163 56285 ...
 $ Odometer_Distance_Mi       : num  8.25 8.55 8.79 9.49 9.67 ...
 $ TravelDistance_Ft          : int  NA 1596 1279 3697 959 229 4330 530 122 977 ...
 $ TravelDistance_Mi          : num  NA 0.302 0.242 0.7 0.182 ...
 $ TravelDistance_Mi_Hvrs     : num  NA 0.15 0.105 0.165 0.832 ...
 $ TD_Mi_SS_q5                : num  NA 0.0252 0.2422 0.7324 0.0794 ...
 $ TD_Mi_SS_q95               : num  NA 0.626 0.242 1.008 0.176 ...
 $ TD_Mi_SSHG_q5              : num  NA 0.0996 0.2422 0.7002 0.1816 ...
 $ TD_Mi_SSHG_q95             : num  NA 0.627 0.242 0.7 0.182 ...
 $ TD_Mi_SS_Mean              : num  NaN 0.437 0.242 0.908 0.128 ...
 $ TD_Mi_SS_Mean_F            : num  NaN 0.457 0.242 0.977 NaN ...
 $ TD_Mi_SSHG_Mean            : num  NaN 0.442 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Mean_F          : num  NaN 0.491 0.242 0.7 0.182 ...
 $ TD_Mi_SS_Med               : num  NA 0.512 0.242 0.962 0.128 ...
 $ TD_Mi_SS_Med_F             : num  NA 0.512 0.242 1.008 NA ...
 $ TD_Mi_SSHG_Med             : num  NA 0.512 0.242 0.7 0.182 ...
 $ TD_Mi_SSHG_Med_F           : num  NA 0.512 0.242 0.7 0.182 ...
 $ TD_Mi_SS_Cnt               : int  0 14 1 4 2 87 22 118 91 11 ...
 $ TD_Mi_SS_Cnt_F             : int  0 12 1 3 0 77 18 106 81 9 ...
 $ TD_Mi_SSHG_Cnt             : int  0 7 1 1 1 23 6 29 28 3 ...
 $ TD_Mi_SSHG_Cnt_F           : int  0 5 1 1 1 19 4 25 24 1 ...
 $ TravelTime_Sec             : num  NA 180 37 25 190 29 288 52 76 8 ...
 $ TT_Sec_SS_q5               : num  NA 11.9 37 30.5 172.9 ...
 $ TT_Sec_SS_q95              : num  NA 346.3 37 75.8 189.1 ...
 $ TT_Sec_SSHG_q5             : num  NA 59.6 37 25 190 11.6 236 51.5 55 8.8 ...
 $ TT_Sec_SSHG_q95            : num  NA 276 37 25 190 ...
 $ TT_Sec_SS_Mean             : num  NaN 215.8 37 58.2 181 ...
 $ TT_Sec_SS_Mean_F           : num  NaN 218.9 37 65.5 NaN ...
 $ TT_Sec_SSHG_Mean           : num  NaN 202 37 25 190 ...
 $ TT_Sec_SSHG_Mean_F         : num  NaN 226 37 25 190 ...
 $ TT_Sec_SS_Med              : num  NA 223.5 37 65.5 181 ...
 $ TT_Sec_SS_Med_F            : num  NA 223.5 37 65.5 NA ...
 $ TT_Sec_SSHG_Med            : num  NA 219 37 25 190 134 286 60 65 16 ...
 $ TT_Sec_SSHG_Med_F          : num  NA 219 37 25 190 134 286 60 65 16 ...
 $ TT_Sec_SS_Cnt              : int  0 14 1 4 2 173 22 141 141 11 ...
 $ TT_Sec_SS_Cnt_F            : int  0 12 1 2 0 156 18 127 128 9 ...
 $ TT_Sec_SSHG_Cnt            : int  0 7 1 1 1 35 6 36 35 3 ...
 $ TT_Sec_SSHG_Cnt_F          : int  0 5 1 1 1 31 4 32 32 1 ...
 $ TravelTime_Hr              : num  NA 0.05 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SS_q5                : num  NA 0.00331 0.01028 0.00849 0.04803 ...
 $ TT_Hr_SS_q95               : num  NA 0.0962 0.0103 0.0211 0.0525 ...
 $ TT_Hr_SSHG_q5              : num  NA 0.01656 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_q95             : num  NA 0.07653 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SS_Mean              : num  NaN 0.0599 0.0103 0.0162 0.0503 ...
 $ TT_Hr_SS_Mean_F            : num  NaN 0.0608 0.0103 0.0182 NaN ...
 $ TT_Hr_SSHG_Mean            : num  NaN 0.05615 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Mean_F          : num  NaN 0.06278 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SS_Med               : num  NA 0.0621 0.0103 0.0182 0.0503 ...
 $ TT_Hr_SS_Med_F             : num  NA 0.0621 0.0103 0.0182 NA ...
 $ TT_Hr_SSHG_Med             : num  NA 0.06083 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SSHG_Med_F           : num  NA 0.06083 0.01028 0.00694 0.05278 ...
 $ TT_Hr_SS_Cnt               : int  0 14 1 4 2 173 22 141 141 11 ...
 $ TT_Hr_SS_Cnt_F             : int  0 12 1 2 0 156 18 127 128 9 ...
 $ TT_Hr_SSHG_Cnt             : int  0 7 1 1 1 35 6 36 35 3 ...
 $ TT_Hr_SSHG_Cnt_F           : int  0 5 1 1 1 31 4 32 28 1 ...
 $ SpeedAvg_Mph               : num  NA 6.05 23.57 100.83 3.44 ...
 $ TravelDistance_Mi_New      : num  NA 0.302 0.242 0.7 0.182 ...
 $ TravelDistance_Mi_New_Label: Factor w/ 65 levels "0.000568181818181818",..: 64 64 64 64 64 64 64 63 63 64 ...

Investigation of TravelDistance_Mi & TravelDistance_Mi_Hvrs & TravelDistance_Mi_New.

Quick summary and then correlation calculation.

summary(select(AllDays_NewTravelDist,
               TravelDistance_Mi,
               TravelDistance_Mi_Hvrs,
               TravelDistance_Mi_New
              )
       )
 TravelDistance_Mi TravelDistance_Mi_Hvrs TravelDistance_Mi_New
 Min.   :  0.0     Min.   : 0.000         Min.   :  0.000      
 1st Qu.:  0.1     1st Qu.: 0.106         1st Qu.:  0.141      
 Median :  0.2     Median : 0.142         Median :  0.199      
 Mean   :  0.3     Mean   : 0.201         Mean   :  0.298      
 3rd Qu.:  0.3     3rd Qu.: 0.193         3rd Qu.:  0.276      
 Max.   :250.7     Max.   :24.407         Max.   :250.656      
 NA's   :322734    NA's   :6528           NA's   :6566         
summary(select(filter(AllDays_NewTravelDist,
                      BusDay_EventNum != 1
                     ),
               TravelDistance_Mi,
               TravelDistance_Mi_Hvrs,
               TravelDistance_Mi_New
              )
       )
 TravelDistance_Mi TravelDistance_Mi_Hvrs TravelDistance_Mi_New
 Min.   :  0.00    Min.   : 0.0000        Min.   :  0.00019    
 1st Qu.:  0.13    1st Qu.: 0.1055        1st Qu.:  0.14072    
 Median :  0.20    Median : 0.1424        Median :  0.19867    
 Mean   :  0.31    Mean   : 0.2008        Mean   :  0.29751    
 3rd Qu.:  0.29    3rd Qu.: 0.1935        3rd Qu.:  0.27633    
 Max.   :250.66    Max.   :24.4068        Max.   :250.65606    
 NA's   :316206                           NA's   :38           
cor(select(AllDays_NewTravelDist,
           TravelDistance_Mi,
           TravelDistance_Mi_Hvrs,
           TravelDistance_Mi_New
          ),
    use = "pairwise.complete.obs"
  )
                       TravelDistance_Mi TravelDistance_Mi_Hvrs
TravelDistance_Mi              1.0000000              0.5447660
TravelDistance_Mi_Hvrs         0.5447660              1.0000000
TravelDistance_Mi_New          0.9513379              0.5837182
                       TravelDistance_Mi_New
TravelDistance_Mi                  0.9513379
TravelDistance_Mi_Hvrs             0.5837182
TravelDistance_Mi_New              1.0000000

Investigation of TravelDistance_Mi & TravelDistance_Mi_Hvrs & TravelDistance_Mi_New.

Graphing the two methods of calculating TravelDistance_Mi.

First, let’s get create a function to plot the liner model equation.

lm_eqn <- function(df, y, x){
  m <- lm(y ~ x, df)
  
  l <- list(a = format(coef(m)[1], digits = 2),
            b = format(abs(coef(m)[2]), digits = 2),
            s1 = ifelse(test = coef(m)[2] > 0,
                        yes = "+",
                        no = "-"
                       ),
            r2 = format(summary(m)$r.squared,
                        digits = 3
                       )
           )
  
  eq <- substitute(italic(y) == a~~s1~~b %.% italic(x)*","~~italic(r)^2~"="~r2,
                   l
                  )
  
  as.character(as.expression(eq)
              )             
}

Investigation of TravelDistance_Mi & TravelDistance_Mi_Hvrs & TravelDistance_Mi_New.

Scatter plot (using a 10% sample to making plotting time faster and to reduce un-needed data in the “same” splot).

set.seed(123456789)
AllDays_NewTravelDist_10Pct <- filter(AllDays_NewTravelDist,
                                      !is.na(TravelDistance_Mi)
                                     ) %>% 
  rename(DistMethod = TravelDistance_Mi_New_Label) %>% 
  sample_frac(0.1)
TravDist_MiVsCalc <- ggplot(select(AllDays_NewTravelDist_10Pct,
                                   TravelDistance_Mi_New,
                                   TravelDistance_Mi,
                                   DistMethod
                                  ),
                            aes(x = TravelDistance_Mi_New,
                                y = TravelDistance_Mi,
                                colour = DistMethod
                               )
                           ) +
  scale_colour_manual(values = c("red","blue", "green", "orange")
                     ) +
  geom_point(shape = 1, alpha = 0.5) +
  scale_shape(solid = FALSE) +
  geom_smooth(method = "lm", colour = "blue") +
  geom_abline(intercept = 0, slope = 1, colour = "red") +
  coord_cartesian(xlim = c(0, 1.5), ylim = c(0, 1.5)
                 ) +
  scale_x_continuous(breaks = seq(0, 1.5, 0.25)
                    ) +
  scale_y_continuous(breaks = seq(0, 1.5, 0.25)
                    ) +
  theme(legend.position = c(0.85, 0.40),
        legend.text = element_text(size = 8)
       ) +
  annotate(label = lm_eqn(df = AllDays_NewTravelDist_10Pct,
                          y = AllDays_NewTravelDist_10Pct$TravelDistance_Mi,
                          x = AllDays_NewTravelDist_10Pct$TravelDistance_Mi_New
                         ),
           # x = 62,
           # y = 20,
           x = 1.15,
           y = 1.45,
           geom = "text",
           size = 3,
           colour = "blue",
           parse = TRUE
          ) +
  annotate(label = "Reference Line (slope = 1)",
           # x = 16,
           # y = 30,
           x = 1.32,
           y = 1.05,
           geom = "text",
           size = 3,
           colour = "red"
          ) +
  labs(title = "TravelDistance_Mi vs. TravelDistance_Mi_New",
       x = "TravelDistance_Mi_New",
       y = "TravelDistance_Mi"
      )
# +
#   geom_jitter()
TravDist_MiVsCalc

Investigation of TravelDistance_Mi & TravelDistance_Mi_Hvrs & TravelDistance_Mi_New.

Graphing test with rbokeh.

TravDist_MiVsCalc_Bokeh <- figure(data = select(AllDays_NewTravelDist_10Pct,
                                                TravelDistance_Mi_New,
                                                TravelDistance_Mi,
                                                DistMethod
                                               ),
                                  xlim = c(0, 1.5),
                                  ylim = c(0, 1.5),
                                  legend_location = "bottom_right"
                                 ) %>% 
  ly_points(x = TravelDistance_Mi_New,
            y = TravelDistance_Mi,
            color = DistMethod,
            hover = c(TravelDistance_Mi_New, TravelDistance_Mi, DistMethod)
           ) %>% 
  ly_abline(a = 0, b = 1, color = "red")
TravDist_MiVsCalc_Bokeh

Investigation of TravelDistance_Mi_New.

~11% of rides are still showing as less than 0.1 miles of TravelDistance_Mi_New.

rm(TravDist_MiVsCalc_Bokeh)
rm(AllDays_NewTravelDist_10Pct)
summary(AllDays_NewTravelDist$TravelDistance_Mi_New)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
  0.000   0.141   0.199   0.298   0.276 250.700    6566 

Investigation of TravelDistance_Mi_New.

Why are there still some small or zero TravelDistance_Mi_New values.

nrow(filter(AllDays_NewTravelDist,
            TravelDistance_Mi_New == 0 &
              BusDay_EventNum != 1
           )
    )
[1] 364

Explore instances where TravelDistance_Mi is NA.


View(group_by(AllDays_NewOrder,
              StartStop_ID
             ) %>% 
       summarise(Cnts = sum(is.na(TravelTime_Sec)
                           )
                ) %>% 
       arrange(desc(Cnts)
              )
    )

View(filter(AllDays_NewOrder,
            StartStop_ID == "5004635--5004758"
           ) %>% 
       select(TravelTime_Sec,
              TT_Sec_SS_Mean,
              TT_Sec_SSHG_Mean,
              TT_Sec_SS_Med,
              TT_Sec_SSHG_Med,
              TT_Sec_SS_Cnt,
              TT_Sec_SSHG_Cnt
              )
    )

Investigation of TravelTime_Hr.

View(TravDistMi_Pctiles): 98% of TravelTime_Hr are between 7 seconds and 464 seconds (~8 minutes).


TravTimeHr_Ntile <- as.data.frame(AllDays_NewTravelDist$TravelTime_Hr) %>% 
  mutate(Pctile = ntile(AllDays_NewTravelDist$TravelTime_Hr, 100),
         MinR = min_rank(AllDays_NewTravelDist$TravelTime_Hr),
         PctR = percent_rank(AllDays_NewTravelDist$TravelTime_Hr),
         PctR_Round = round(PctR, 2)
        ) 

colnames(TravTimeHr_Ntile)[1] <- "TravelTime_Hr"
str(TravTimeHr_Ntile)

TravTimeHr_Ntile_Rows <- nrow(TravTimeHr_Ntile)

View(tail(TravTimeHr_Ntile, 500))


TravTimeHr_Pctiles <- group_by(TravTimeHr_Ntile,
                               PctR_Round
                              ) %>% 
  summarise(
    MinTravTimeHrAtPctile = min(TravelTime_Hr),
    CntsAtPctile = n(),
    PctsAtPctile = CntsAtPctile / TravTimeHr_Ntile_Rows
  ) %>% 
  mutate(CumSumPAtP = cumsum(PctsAtPctile),
         MinTravTimeSecAtPctile = MinTravTimeHrAtPctile * 3600
        )

View(TravTimeHr_Pctiles)

Investigation of TravelTime_Hr.

Histogram of TravelTime_Sec.


TravTime_Sec_HistDen <- ggplot(filter(AllDays_NewTravelDist,
                                      !is.na(TravelTime_Sec)
                                     ),
                               aes(x = TravelTime_Sec,
                                   y = ..density..
                                  )
                          ) +
  geom_histogram(binwidth = 5, fill = "lightblue", colour = "grey60", size = 0.2) +
  geom_line(stat = "density", colour = "red") +
  # stat_bin(binwidth = 5,
  #          geom = "text",
  #          size = 2.5,
  #          vjust = 1.5,
  #          aes(label = format(..count.., big.mark = ",")
  #             ),
  #         ) +
  coord_cartesian(xlim = c(0, 180), ylim = c(0, 0.02)
                 ) +
  #  theme(legend.position="none") +
  labs(title = "Variation in Travel Time",
       x = "Travel Time (sec)",
       y = "Density"
      )

TravTime_Sec_HistDen

Investigation of TravelTime_Hr.

Looking at odd TravelTime_Sec values.


View(filter(AllDays_NewTravelDist,
            is.na(TravelTime_Sec) & 
              !is.na(Odometer_Distance_Lag1)
           )
    )


# examples of TravelTime_Sec values that are NA. These are NA because the Event_Time & Departure_Time readings are not accurate (i.e., the previous Departure_Time is BEFORE the current Event_Time).
View(filter(AllDays_NewTravelDist,
            (RowNum_OG >= 90809 & RowNum_OG <= 90829) | # 90819
                (RowNum_OG >= 90881 & RowNum_OG <= 90901) | # 90891
                (RowNum_OG >= 994813 & RowNum_OG <= 994833) | # 994823
                (RowNum_OG >= 2391342 & RowNum_OG <= 2391362) # 2391352
           )
    )


View(filter(AllDays_NewTravelDist,
            TravelTime_Sec == 0
           )
    )

# examples where TravelTime_Sec is zero (i.e., previous Departure_Time equals the current Event_Time).
View(filter(AllDays_NewTravelDist,
            (RowNum_OG >= 175725 & RowNum_OG <= 175745) | # 175735
                (RowNum_OG >= 401127 & RowNum_OG <= 401147) | # 401137
                (RowNum_OG >= 2446820 & RowNum_OG <= 2446840) | # 2446830
                (RowNum_OG >= 2545036 & RowNum_OG <= 2545056) # 2545046
           )
    )


View(filter(AllDays_NewTravelDist,
            TravelTime_Sec > 0 &
              TravelTime_Sec < 10
           ) %>% 
       arrange(desc(SpeedAvg_Mph)
              )
    )


# examples where TravelTime_Sec is unusually small (with TravelDistance_Mi values that are large).
View(filter(AllDays_NewTravelDist,
            (RowNum_OG >= 1042228 & RowNum_OG <= 1042248) | # 1042238
                (RowNum_OG >= 53816 & RowNum_OG <= 53836) | # 53826
                (RowNum_OG >= 360571 & RowNum_OG <= 360591) | # 360581
                (RowNum_OG >= 502271 & RowNum_OG <= 502291) # 502281 (can't explian the weird TravelTime_Sec calculation here - it's not even an integer!)
           )
    )

# still trying to explain 502281...on the day of this weirdness, the bus was only in circulation for 4-5 stops (~20 minutes) on that day (Oct 6)
View(filter(AllDays_NewTravelDist,
            Bus_ID == 2711
           )
    )


# exploring large values for TravelTime_Sec
View(filter(AllDays_NewTravelDist,
            TravelTime_Sec == 300
           ) %>% 
       arrange(desc(TravelTime_Sec),
               SpeedAvg_Mph2
              )
    )

# examples where TravelTime_Sec is unusually large (with TravelDistance_Mi values that are small, so SpeedAvg_Mph values are very small).
View(filter(AllDays_NewTravelDist,
            (RowNum_OG >= 2627459 & RowNum_OG <= 2627479) | # 2627469
                (RowNum_OG >= 2193344 & RowNum_OG <= 2193364) | # 2193354
                (RowNum_OG >= 1644123 & RowNum_OG <= 1644143) | # 1644133
                (RowNum_OG >= 869600 & RowNum_OG <= 869620) # 869610
           )
    )

Investigation of SpeedAvg_Mph2

View(Speed_Pctiles): 90% of SpeedAvg_Mph2 are between ~3mph and ~66mph.


Speed_Ntile <- as.data.frame(AllDays_NewTravelDist$SpeedAvg_Mph2) %>% 
  mutate(Pctile = ntile(AllDays_NewTravelDist$SpeedAvg_Mph2, 100),
         MinR = min_rank(AllDays_NewTravelDist$SpeedAvg_Mph2),
         PctR = percent_rank(AllDays_NewTravelDist$SpeedAvg_Mph2),
         PctR_Round = round(PctR, 2)
        ) 

colnames(Speed_Ntile)[1] <- "SpeedAvg_Mph2"
str(Speed_Ntile)

Speed_Ntile_Rows <- nrow(Speed_Ntile)

View(tail(Speed_Ntile, 500))


Speed_Pctiles <- group_by(Speed_Ntile,
                          PctR_Round
                         ) %>% 
  summarise(
    MinSpeedAtPctile = min(SpeedAvg_Mph2),
    CntsAtPctile = n(),
    PctsAtPctile = CntsAtPctile / Speed_Ntile_Rows
  ) %>% 
  mutate(CumSumPAtP = cumsum(PctsAtPctile)
        )

View(Speed_Pctiles)

Investigation of SpeedAvg_Mph2.

Exploring the removal of outlier TravelTime_Sec and TravelDistance_Mi.


summary(select(AllDays_NewTravelDist,
               SpeedAvg_Mph,
               SpeedAvg_Mph2
              )
       )

summary(select(filter(AllDays_NewTravelDist,
                      TravelDistance_Mi > 0.0001893939 & # lowest non-zero percentile
                        TravelDistance_Mi < 1.0812500000 & # 99th percentile
                        TravelTime_Sec > 10.050000 & # 2nd percentile
                        TravelTime_Sec < 293.000000 # 98th percentile
                     ),
               SpeedAvg_Mph,
               SpeedAvg_Mph2
              )
       )

Investigation of SpeedAvg_Mph2.

Histogram of SpeedAvg_Mph2.


Speed_HistDen <- ggplot(filter(AllDays_NewTravelDist,
                               !is.na(SpeedAvg_Mph2)
                              ),
                        aes(x = SpeedAvg_Mph2,
                            y = ..density..
                           )
                       ) +
  geom_histogram(binwidth = 5, fill = "lightblue", colour = "grey60", size = 0.2) +
  geom_line(stat = "density", colour = "red") +
  stat_bin(binwidth = 5,
           geom = "text",
           size = 2.5,
           vjust = 1.5,
           aes(label = format(..count.., big.mark = ",")
              ),
          ) +
  # geom_text(aes(label = format(..count.., big.mark = ",")
  #              ),
  #           size = 3,
  #           nudge_y = (..count.. * 0.1)
  #          ) +
  coord_cartesian(xlim = c(0, 70), ylim = c(0, 0.04)
                 ) +
  #  theme(legend.position="none") +
  labs(title = "Variation in Travel Speed",
       x = "Average Speed (mph)",
       y = "Density"
      )

Speed_HistDen

Investigation of SpeedAvg_Mph2.

Histogram of SpeedAvg_Mph2 after removing outlier TravelTime_Sec and TravelDistance_Mi.


View(TravDistMiNew_Pctiles)
View(TravTimeHr_Pctiles)

SpeedNoOutlier_HistDen <- ggplot(filter(AllDays_NewTravelDist,
                                        !is.na(SpeedAvg_Mph2) &
                                          TravelDistance_Mi_New > 0.077841005 & # 5th percentile
                                          # TravelDistance_Mi_New < 1.0812500000 & # 99th percentile
                                          TravelTime_Sec > 12.100000 # 4th percentile
                                          # TravelTime_Sec < 293.000000 # 98th percentile
                                       ),
                                 aes(x = SpeedAvg_Mph2,
                                     y = ..density..
                                    )
                                ) +
  geom_histogram(binwidth = 5, fill = "lightblue", colour = "grey60", size = 0.2) +
  geom_line(stat = "density", colour = "red") +
  stat_bin(binwidth = 5,
           geom = "text",
           size = 2.5,
           vjust = 1.5,
           aes(label = format(..count.., big.mark = ",")
              ),
          ) +
  # geom_text(aes(label = format(..count.., big.mark = ",")
  #              ),
  #           size = 3,
  #           nudge_y = (..count.. * 0.1)
  #          ) +
  coord_cartesian(xlim = c(0, 70), ylim = c(0, 0.04)
                 ) +
  #  theme(legend.position="none") +
  labs(title = "Variation in Travel Speed",
       subtitle = "(removed low outliers of Travel Distance and Travel Time)",
       x = "Average Speed (mph)",
       y = "Density"
      )

SpeedNoOutlier_HistDen

Investigation of SpeedAvg_Mph2.

New dataset (NoOutliers_TravelDistNTime) when removing outlier low values of TravelDistance_Mi_New and TravelTime_Sec.


View(TravDistMiNew_Pctiles)
View(TravTimeHr_Pctiles)

NoOutliers_TravelDistNTime <- filter(AllDays_NewTravelDist,
                                     TravelDistance_Mi_New > .077841005 & # 5th percentile
                                       # TravelDistance_Mi_New < 1.0812500000 & # 99th percentile
                                       TravelTime_Sec > 12.100000 # 4th percentile
                                       # TravelTime_Sec < 293.000000 # 98th percentile
                                    )

nrow(AllDays_NewTravelDist) - nrow(NoOutliers_TravelDistNTime)

str(NoOutliers_TravelDistNTime)
summary(NoOutliers_TravelDistNTime)

Investigation of SppedAvg_Mph2.

View(Speed_NoOut_Pctiles): Aproximately 90% of SpeedAvg_Mph2 values are between ~4mph and ~56mph.


Speed_NoOut_Ntile <- as.data.frame(NoOutliers_TravelDistNTime$SpeedAvg_Mph2) %>% 
  mutate(Pctile = ntile(NoOutliers_TravelDistNTime$SpeedAvg_Mph2, 100),
         MinR = min_rank(NoOutliers_TravelDistNTime$SpeedAvg_Mph2),
         PctR = percent_rank(NoOutliers_TravelDistNTime$SpeedAvg_Mph2),
         PctR_Round = round(PctR, 2)
        ) 

colnames(Speed_NoOut_Ntile)[1] <- "SpeedAvg_Mph2"
str(Speed_NoOut_Ntile)

Speed_NoOut_Ntile_Rows <- nrow(Speed_NoOut_Ntile)

View(tail(Speed_NoOut_Ntile, 500))


Speed_NoOut_Pctiles <- group_by(Speed_NoOut_Ntile,
                                PctR_Round
                               ) %>% 
  summarise(
    MinSpeedAtPctile = min(SpeedAvg_Mph2),
    CntsAtPctile = n(),
    PctsAtPctile = CntsAtPctile / Speed_NoOut_Ntile_Rows
  ) %>% 
  mutate(CumSumPAtP = cumsum(PctsAtPctile)
        )

View(Speed_NoOut_Pctiles)

Investigation of SppedAvg_Mph2.

Exloring odd/impossible values.


# Exploring when SpeedAvg_Mph2 is NA  --  does not occur at all
nrow(filter(NoOutliers_TravelDistNTime,
            is.na(SpeedAvg_Mph2)
           )
    )


# Exploring when SpeedAvg_Mph2 is zero  --  does not occur at all
nrow(filter(NoOutliers_TravelDistNTime,
            SpeedAvg_Mph2 == 0
           )
    )


# examples where SpeedAvg_Mph2 < 3.2848770
View(filter(AllDays_NewTravelDist,
            SpeedAvg_Mph2 > 0 &
              SpeedAvg_Mph2 < 3.2848770
           ) %>% 
       arrange(SpeedAvg_Mph2)
    )

# examples where SpeedAvg_Mph2 < 3.2848770
View(filter(AllDays_NewTravelDist,
            (RowNum_OG >= 485338 & RowNum_OG <= 485358) | # 485348  --  Extreme travel time, Route Change
                (RowNum_OG >= 346952 & RowNum_OG <= 346972) | # 346962  -- Extreme travel time, Route Change 
                (RowNum_OG >= 70494 & RowNum_OG <= 70514) | # 70504  --  Extreme travel time, Route Change
                (RowNum_OG >= 2051846 & RowNum_OG <= 2051866) # 2051856  --  Extreme travel time, Route Change
           )
    )

Investigation of SpeedAvg_Mph2.

Limit the dataset based on SpeedAvg_Mph2.


NoOutliersSpeed <- filter(NoOutliers_TravelDistNTime,
                          between(SpeedAvg_Mph2,
                                  4.069300, # 5th percentile
                                  56.05651 #95th percentile
                                 )
                          )

nrow(NoOutliers_TravelDistNTime) - nrow(NoOutliersSpeed)

summary(NoOutliersSpeed)

TravelTime now looks like it has some odd values on the high end. So let’s look at those.

View(TravTime_NoOut_Pctiles): Virtually all trips should take less than 5 minutes. (The 99th percentile of of TravelTime is approximately 8 minutes.)


TravTime_NoOut_Ntile <- as.data.frame(NoOutliersSpeed$TravelTime_Hr) %>% 
  mutate(Pctile = ntile(NoOutliersSpeed$TravelTime_Hr, 100),
         MinR = min_rank(NoOutliersSpeed$TravelTime_Hr),
         PctR = percent_rank(NoOutliersSpeed$TravelTime_Hr),
         PctR_Round = round(PctR, 2)
        )

colnames(TravTime_NoOut_Ntile)[1] <- "TravelTime_Hr"
str(TravTime_NoOut_Ntile)

TravTime_NoOut_Ntile_Rows <- nrow(TravTime_NoOut_Ntile)

View(tail(TravTime_NoOut_Ntile, 500))


TravTime_NoOut_Pctiles <- group_by(TravTime_NoOut_Ntile,
                                   PctR_Round
                                  ) %>% 
  summarise(
    MinTravTimeHrAtPctile = min(TravelTime_Hr),
    CntsAtPctile = n(),
    PctsAtPctile = CntsAtPctile / TravTime_NoOut_Ntile_Rows
  ) %>% 
  mutate(CumSumPAtP = cumsum(PctsAtPctile),
         MinTravTimeSecAtPctile = MinTravTimeHrAtPctile * (60 * 60)
        )

View(TravTime_NoOut_Pctiles)

Investigating odd TravelTime_Sec values.

Trips longer than ~8 minutes.


View(filter(NoOutliersSpeed,
            TravelTime_Sec > 491 # min at the 100th percentile
           ) %>% 
       arrange(desc(TravelTime_Sec)
              )
    )

# examples of TravelTime_Sec values that are largest.
View(filter(NoOutliersSpeed,
            (RowNum_OG >= 2071759 & RowNum_OG <= 2071779) | # 2071769  --  results from a route change, and a 3hr+ wait before the new route starts
                (RowNum_OG >= 1473686 & RowNum_OG <= 1473706) | # 1473696  --  results from a route change, and a 3hr wait before the new route starts
                (RowNum_OG >= 1222822 & RowNum_OG <= 1222842) | # 1222832  --  results from a route change, and a 3hr wait before the new route starts
                (RowNum_OG >= 3046089 & RowNum_OG <= 3046109) # 3046099  --  results from a route change, and a 3hr wait before the new route starts
           )
    )


# examples of TravelTime_Sec values that are the smallest of the large.
View(filter(NoOutliersSpeed,
            (RowNum_OG >= 3044689 & RowNum_OG <= 3044709) | # 3044699  --  results from a route change
                (RowNum_OG >= 3022358 & RowNum_OG <= 3022378) | # 3022368  --  results from a route change
                (RowNum_OG >= 2993016 & RowNum_OG <= 2993036) | # 2993026  --  results from a previous route change (change occurred in deleted row)
                (RowNum_OG >= 2683703 & RowNum_OG <= 2683723) # 2683713  --  results from a previous route change (change occurred in deleted row)
           )
    )

Let’s look at the TravelTime_Sec values and route changes (DirChange2).

The 99th percentile of TravelTime_Sec for both, all trips, and just those trips NOT involving route changes (DirChange2 = “Same”), is approximately 5min (300 sec).

Nota Bene: The percentile calculation here is defined slightly different than in most of the above analyses (which get the lowest value in the bin created by 100 ntiles).


summary(select(NoOutliersSpeed,
               TravelTime_Sec
              )
       )

summary(select(filter(NoOutliersSpeed,
                      DirChange2 == "Same"
                     ),
               TravelTime_Sec
              )
       )

summary(select(filter(NoOutliersSpeed,
                      DirChange2 == "Change"
                     ),
               TravelTime_Sec
              )
       )


TravTimeSec_Qtiles_df <- data.frame(PctValue = seq(0, 100, 1),
                                    All = seq(1, 101, 1),
                                    Same = seq(1, 101, 1),
                                    Change = seq(1, 101, 1)
                                   )

TravTimeSec_Qtiles_df[ , 2] <- quantile(select(NoOutliersSpeed,
                                               TravelTime_Sec
                                              ),
                                        probs = seq(0, 1, 0.01),
                                        na.rm = TRUE
                                       )

TravTimeSec_Qtiles_df[ , 3] <- quantile(select(filter(NoOutliersSpeed,
                                                      DirChange2 == "Same"
                                                     ),
                                               TravelTime_Sec
                                              ),
                                        probs = seq(0, 1, 0.01),
                                        na.rm = TRUE
                                       )

TravTimeSec_Qtiles_df[ , 4] <- quantile(select(filter(NoOutliersSpeed,
                                                      DirChange2 == "Change"
                                                     ),
                                               TravelTime_Sec
                                              ),
                                        probs = seq(0, 1, 0.01),
                                        na.rm = TRUE
                                       )

View(TravTimeSec_Qtiles_df)

Limit the dataset now based on TravelTime_Sec.


UpperLimitTravTime <- filter(NoOutliersSpeed,
                             TravelTime_Sec <= 491 # min at the 100th percentile
                             )

nrow(NoOutliersSpeed) - nrow(UpperLimitTravTime)

str(UpperLimitTravTime)

summary(UpperLimitTravTime)

Investigation of Dwell_Time2 (how long the bus is at a stop).

Differences between Dwell_Time (by WMATA) and Dwell_Time2 (by me) appear to be due to switches in RouteAlt. WMATA calculates Dwell_Time by an unknown process. The WMATA calculation is equal to my calculation, except for the records immedaitely before and after a RouteAlt switch (DirChange2).


View(filter(AllDays_NewOrder,
            Dwell_Time != Dwell_Time2
           )
    )


# Examples where the Dwell_Time and Dwell_Time2 are different
View(filter(AllDays_NewOrder,
            ( (RowNum_OG >= 65 & RowNum_OG <= 85) | # 75
                (RowNum_OG >= 162 & RowNum_OG <= 192) | # 172
                (RowNum_OG >= 431952 & RowNum_OG <= 431972) | # 431962
                (RowNum_OG >= 434595 & RowNum_OG <= 434615) # 434605  --  this record is NOT a route switch, but does has a Sequence switch (Me: should there really be a route switch here?)
            )
           )
    )

Investigation of Dwell_Time2 (how long the bus is at a stop).

First, create some “rank” stats. View(DT2_Pctiles): 95% of Dwell_Time2s are <= 23 seconds…but some weird (e.g., nearly 2 hour Dwell_Time2s exist).


DwellTime2_Ntile <- as.data.frame(AllDays_NewOrder$Dwell_Time2) %>% 
  mutate(Pctile = ntile(AllDays_NewOrder$Dwell_Time2, 100),
         MinR = min_rank(AllDays_NewOrder$Dwell_Time2),
         PctR = percent_rank(AllDays_NewOrder$Dwell_Time2),
         PctR_Round = round(PctR, 2)
        ) 

colnames(DwellTime2_Ntile)[1] <- "Dwell_Time2"
str(DwellTime2_Ntile)

DwellTime2_Ntile_Rows <- nrow(DwellTime2_Ntile)

View(tail(DwellTime2_Ntile, 500))


DwellTime2_Pctiles <- group_by(DwellTime2_Ntile,
                               PctR_Round
                              ) %>% 
  summarise(
    MinDwellAtPctile = min(Dwell_Time2),
    CntsAtPctile = n(),
    PctsAtPctile = CntsAtPctile / DwellTime2_Ntile_Rows
  ) %>% 
  mutate(CumSumPAtP = cumsum(PctsAtPctile)
        )

View(DwellTime2_Pctiles)

Investigation of Dwell_Time2 (how long the bus is at a stop).

Histogram of Dwell_Time2.


DwellTime2_HistDen <- ggplot(AllDays_NewOrder, aes(x = Dwell_Time2, y = ..density..)) +
  geom_histogram(binwidth = 1, fill = "lightblue", colour = "grey60", size = 0.2) +
  geom_line(stat = "density", colour = "red") +
  coord_cartesian(xlim = c(1, 25), ylim = c(0, 0.05)
                 ) +
  xlab("Time a Bus Stays at a Stop (sec)") + 
  ylab("Density") + 
  #  theme(legend.position="none") + 
  ggtitle(expression(atop("Variation in How Long a Bus Stays at a Stop"
                          # ,atop(italic("xxxxx"),"")
                         )
                    )
         )

DwellTime2_HistDen

Investigation of Dwell_Time2 (how long the bus is at a stop).

Looking at some weirdly long Dwell_Time2 values.


View(arrange(AllDays_NewOrder,
             desc(Dwell_Time2)
            )
    )


# examples of extremely large Dwell_Time2s
View(filter(AllDays_NewOrder,
            (RowNum_OG >= 292669 & RowNum_OG <= 292689) | # 292679
                (RowNum_OG >= 531057 & RowNum_OG <= 531077) | # 531067
                (RowNum_OG >= 1388627 & RowNum_OG <= 1388647) | # 1388637
                (RowNum_OG >= 1645711 & RowNum_OG <= 1645731) # 1645721
           )
    )


View(filter(AllDays_NewOrder,
            Dwell_Time2 == 0
           )
    )

Investigation of Delta_Time (how early or late the bus is).

View(DT2_Pctiles): 94% of Delta_Time values are between -236 seconds and 1,259 seconds. Roughly 66% of records are within 5 min late and 5 min early…but some weird (e.g., almost 50 minute late or 40 minute early) Delta_Times exist.

Note that Delta_Time is the difference from the scheduled bus arrival. So if two buses are scheduled to arrive at a destination at 10:00pm and 10:20pm, and if the 10:20pm bus has a Delta_Time of 5 minutes, there are 25 minutes between bus arrivals at the stop.

Also note that based on a comment at https://planitmetro.com/2016/11/16/data-download-metrobus-vehicle-location-data/, the Delta_Time values don’t appear to coincide with published bus schedules (e.g., the X2 departing every 8 minutes during peak hours).


DeltTime_Ntile <- as.data.frame(AllDays_NewOrder$Delta_Time) %>% 
  mutate(Pctile = ntile(AllDays_NewOrder$Delta_Time, 100),
         MinR = min_rank(AllDays_NewOrder$Delta_Time),
         PctR = percent_rank(AllDays_NewOrder$Delta_Time),
         PctR_Round = round(PctR, 2)
        ) 

colnames(DeltTime_Ntile)[1] <- "Delta_Time"
str(DeltTime_Ntile)

DeltTime_Ntile_Rows <- nrow(DeltTime_Ntile)

View(tail(DeltTime_Ntile, 500))


DeltTime_Pctiles <- group_by(DeltTime_Ntile,
                             PctR_Round
                            ) %>% 
  summarise(
    MinDeltTimeAtPctile = min(Delta_Time),
    CntsAtPctile = n(),
    PctsAtPctile = CntsAtPctile / DeltTime_Ntile_Rows
  ) %>% 
  mutate(CumSumPAtP = cumsum(PctsAtPctile)
        )

View(DeltTime_Pctiles)
DeltTime_Pctiles

# ~66% of rows are between 5 min late and 5 min early
nrow(filter(AllDays_NewOrder,
            Delta_Time >= -300 &
              Delta_Time <= 300
           )
    ) / nrow(AllDays_NewOrder)


# examples of weird large Delta_Times
View(filter(AllDays_NewOrder,
            Delta_Time < -4202 |
              Delta_Time > 1705
           ) %>% 
       arrange(desc(Delta_Time)
              )
    )

Investigation of Delta_Time (how early or late the bus is).

Delta_Time histogram.


DeltTime_HistDen <- ggplot(AllDays_NewOrder, aes(x = (Delta_Time / 60),
                                                 y = ..density..
                                                )
                          ) +
  geom_histogram(binwidth = (5/60), fill = "lightblue", colour = "grey60", size = 0.2) +
  geom_line(stat = "density", colour = "red") +
  coord_cartesian(xlim = c(-5, 5)) +
  xlab("Bus Lateness (min)") + 
  ylab("Density") + 
  #  theme(legend.position="none") + 
  ggtitle(expression(atop("Variation in How Early/Late a Bus Is",
                          atop(italic("(positive values are late arrivals)"),
                               ""
                              )
                         )
                    )
         )

DeltTime_HistDen

Investigation of Delta_Time (how early or late the bus is).

Delta_Time boxplot.


# Count_Values is needed to display the medians on the box plots
Count_Values <- ddply(AllDays_NewOrder,
                      .(Event_Time_HrGroup),
                      summarise,
                      Value_Counts = median(Delta_Time / 60, na.rm = TRUE)
                     )

DeltTime_BoxPlot <- ggplot(AllDays_NewOrder,
                           aes(factor(Event_Time_HrGroup),
                               Delta_Time / 60,
                               fill = factor(Event_Time_HrGroup)
                              )
                          ) + 
  geom_boxplot(outlier.colour="red", notch=TRUE) + 
  # coord_cartesian(ylim = c(-300, 1200)) +
  coord_cartesian(ylim = c(-5, 20)) +
  geom_text(data = Count_Values,
            aes(y = Value_Counts,
                label = format(round(Value_Counts, digits = 1),
                               nsmall = 1
                              )
               ),
            size = 3,
            vjust = -0.5
           ) +
  xlab("Hour Group") + 
  ylab("Bus Lateness (minutes)") + 
  theme(legend.position="none", axis.text.x = element_text(angle=45)) + 
  #theme(legend.position="right", axis.text.x = element_blank()) + 
  ggtitle(expression(atop("How Early/Late is the Bus (by Hour Group)",
                          atop(italic("(positive values are late arrivals)"),
                               ""
                              )
                         )
                    )
         )

DeltTime_BoxPlot

Investigation of Delta_Time (how early or late the bus is).

Exploring “extreme” Delta_Times. First let’s get some “rank” stats.


View(DeltTime_Pctiles)
DeltTime_Pctiles


DeltTimeAbs_Ntile <- as.data.frame(abs(AllDays_NewOrder$Delta_Time)) %>% 
  mutate(Pctile = ntile(abs(AllDays_NewOrder$Delta_Time), 100),
         MinR = min_rank(abs(AllDays_NewOrder$Delta_Time)),
         PctR = percent_rank(abs(AllDays_NewOrder$Delta_Time)),
         PctR_Round = round(PctR, 2)
        ) 

colnames(DeltTimeAbs_Ntile)[1] <- "Delta_Time_Abs"
str(DeltTimeAbs_Ntile)

DeltTimeAbs_Ntile_Rows <- nrow(DeltTimeAbs_Ntile)

View(tail(DeltTimeAbs_Ntile, 500))


DeltTimeAbs_Pctiles <- group_by(DeltTimeAbs_Ntile,
                                PctR_Round
                               ) %>% 
  summarise(
    MinDeltTimeAtPctile = min(Delta_Time_Abs),
    CntsAtPctile = n(),
    PctsAtPctile = CntsAtPctile / DeltTime_Ntile_Rows
  ) %>% 
  mutate(CumSumPAtP = cumsum(PctsAtPctile)
        )

View(DeltTimeAbs_Pctiles)
DeltTimeAbs_Pctiles

Investigation of Delta_Time (how early or late the bus is).

Exploring “extreme” Delta_Times. Then let’s calculate the percentage of buses that are 10 minutes (or more) late/early.


HrGroup_DeltaTime_All <- group_by(AllDays_NewOrder,
                                  Event_Time_HrGroup
                                 ) %>% 
  summarise(EventAll_Cnt = n()
           )

str(HrGroup_DeltaTime_All)
View(HrGroup_DeltaTime_All)


HrGroup_DeltaTime_Above10Min <- filter(AllDays_NewOrder,
                                       abs(Delta_Time) >= 600
                                      ) %>% 
  group_by(Event_Time_HrGroup) %>% 
  summarise(EventAbove10_Cnt = n()
           )

str(HrGroup_DeltaTime_Above10Min)
View(HrGroup_DeltaTime_Above10Min)


HrGroup_DeltaTimeCompare <- inner_join(HrGroup_DeltaTime_Above10Min,
                                       HrGroup_DeltaTime_All,
                                       by = c("Event_Time_HrGroup" = "Event_Time_HrGroup")
                                      ) %>% 
  mutate(PctEventsAbove10 = EventAbove10_Cnt / EventAll_Cnt)

View(HrGroup_DeltaTimeCompare)

Investigation of Delta_Time (how early or late the bus is).

Quickly plot these “extreme” Delta_Times.


DeltTime_Above10_Cols <- ggplot(HrGroup_DeltaTimeCompare,
                                aes(factor(Event_Time_HrGroup),
                                    PctEventsAbove10
                                   )
                               ) +
  geom_col(fill = "lightblue", colour = "grey60", size = 0.2) +
  geom_text(aes(label = format(round(PctEventsAbove10, digits = 2),
                               nsmall = 2
                              )
               ),
            size = 3,
            nudge_y = (HrGroup_DeltaTimeCompare$PctEventsAbove10 * -0.1)
           ) +
  # coord_cartesian(xlim = c(-5, 5)) +
  xlab("Hour Group") + 
  ylab("Percent of All Bus Arrivals") +
  theme(legend.position="none", axis.text.x = element_text(angle=45)) +
  ggtitle(expression(atop("When is a Bus 10+ Minutes Late/Early"
                          # ,atop(italic("positive values are late arrivals"),
                          #      ""
                          #     )
                         )
                    )
         )

DeltTime_Above10_Cols

Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).

Correlation.


DwellTDeltaT_Corr <- as.matrix(cor(x = AllDays_NewOrder$Dwell_Time2,
                                   y = AllDays_NewOrder$Delta_Time,
                                   use = "pairwise"
                                  )
                               )

DwellTDeltaT_Corr

Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).

Next, let’s get a sample of data for plotting. Let’s do this for the full dataset (AllDays_NewOrder).


AllDays_NewOrder_10PctSamp <- sample_frac(AllDays_NewOrder, 0.1) %>% 
  select(Delta_Time,
         Dwell_Time2
        ) %>% 
  mutate(DataSet = "AllData")

str(AllDays_NewOrder_10PctSamp)

Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).

Let’s also get a sample of data for plotting, but with a datset that removes outliers.


View(DeltTime_Pctiles)
View(DwellTime2_Pctiles)

AllDays_NewOrder_NoExtremes_10PctSamp <- filter(AllDays_NewOrder,
                                                between(Delta_Time, -402, 1705) & # removes about 2% of Delta_Time values
                                                  between(Dwell_Time2, 1, 63)  # removes about 2% of Dwell_Time2 values
                                               ) %>% 
  sample_frac(0.1) %>% 
  select(Delta_Time,
         Dwell_Time2
        ) %>% 
  mutate(DataSet = "OutliersRemoved")

str(AllDays_NewOrder_NoExtremes_10PctSamp)

Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).

Plotting the data from the dataset that does not remove outliers.


DwellTDeltaT_Scatter <- ggplot(AllDays_NewOrder_10PctSamp,
                               aes(Dwell_Time2, Delta_Time)
                              ) +
  geom_point(shape = 1, alpha = 0.5) +
  scale_shape(solid = FALSE) +
  geom_smooth(method = "lm", colour = "red") +
  # xlab("Time at Stop (sec)") + 
  # ylab("Lateness (sec)") +
  annotate(label = lm_eqn(df = AllDays_NewOrder_10PctSamp,
                          y = AllDays_NewOrder_10PctSamp$Delta_Time,
                          x = AllDays_NewOrder_10PctSamp$Dwell_Time2
                         ),
           x = 2200,
           y = 600,
           geom = "text",
           size = 3,
           colour = "red",
           parse = TRUE
          ) +
  labs(title = "Lateness vs Time at Stop",
       subtitle = "(no outliers removed)",
       x = "Time at Stop (sec)",
       y = "Lateness (sec)"
      )
  # ggtitle(expression(atop("Lateness vs Time at Stop"
  #                         ,atop(italic("(no outliers removed)"),
  #                               ""
  #                              )
  #                        )
  #                   )
  #        )
# +
#   geom_jitter()

DwellTDeltaT_Scatter

Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).

Plotting the data from the dataset that does remove outliers.


DwellTDeltaT_Scatter_NoExtremes <- ggplot(AllDays_NewOrder_NoExtremes_10PctSamp,
                                          aes(Dwell_Time2, Delta_Time)
                                         ) +
  geom_point(shape = 1, alpha = 0.5) +
  scale_shape(solid = FALSE) +
  geom_smooth(method = "lm", colour = "blue") +
  # xlab("Time at Stop (sec)") + 
  # ylab("Lateness (sec)") +
  annotate(label = lm_eqn(df = AllDays_NewOrder_NoExtremes_10PctSamp,
                          y = AllDays_NewOrder_NoExtremes_10PctSamp$Delta_Time,
                          x = AllDays_NewOrder_NoExtremes_10PctSamp$Dwell_Time2
                         ),
           x = 50,
           y = -475,
           geom = "text",
           size = 3,
           colour = "blue",
           parse = TRUE
          ) +
  labs(title = "Lateness vs Time at Stop",
       subtitle = "(2% of outliers removed)",
       x = "Time at Stop (sec)",
       y = "Lateness (sec)"
      )
  # ggtitle(expression(atop("Lateness vs Time at Stop"
  #                         ,atop(italic("(2% of outliers removed)"),
  #                               ""
  #                              )
  #                        )
  #                   )
  #        )
# +
#   geom_jitter()

DwellTDeltaT_Scatter_NoExtremes

Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).

Plotting the data from both datasets together.


CombinedData <- rbind(AllDays_NewOrder_10PctSamp,
                      AllDays_NewOrder_NoExtremes_10PctSamp
                     )

CombinedData$DataSet <- factor(CombinedData$DataSet)

str(CombinedData)


DwellTDeltaT_Scatter_Combined <- ggplot(CombinedData,
                                        aes(x = Dwell_Time2,
                                            y = Delta_Time,
                                            colour = DataSet
                                           )
                                       ) +
  geom_point(shape = 1, alpha = 0.5) +
  scale_shape(solid = FALSE) +
  coord_cartesian(xlim = c(0, 500), ylim = c(-1000, 2000)
                 ) +
  geom_smooth(data = filter(CombinedData,
                            DataSet == "AllData"
                           ),
              method = "lm",
              colour = "red"
             ) +
  geom_smooth(data = filter(CombinedData,
                            DataSet == "OutliersRemoved"
                           ),
              method = "lm",
              colour = "blue"
             ) +
  # facet_wrap( ~ DataSet, ncol = 2) +
  annotate(label = lm_eqn(df = AllDays_NewOrder_10PctSamp,
                          y = AllDays_NewOrder_10PctSamp$Delta_Time,
                          x = AllDays_NewOrder_10PctSamp$Dwell_Time2
                         ),
           x = 300,
           y = -600,
           geom = "text",
           size = 3,
           colour = "red",
           parse = TRUE
          ) +
  annotate(label = lm_eqn(df = AllDays_NewOrder_NoExtremes_10PctSamp,
                          y = AllDays_NewOrder_NoExtremes_10PctSamp$Delta_Time,
                          x = AllDays_NewOrder_NoExtremes_10PctSamp$Dwell_Time2
                         ),
           x = 300,
           y = -800,
           geom = "text",
           size = 3,
           colour = "blue",
           parse = TRUE
          ) +
  theme(legend.position = "bottom") +
  labs(title = "Lateness vs Time at Stop",
       x = "Time at Stop (sec)",
       y = "Lateness (sec)"
      )
  # ggtitle(expression(atop("Lateness vs Time at Stop"
                          # ,atop(italic("2% of outliers removed"),
                          #       ""
                          #      )
         #                 )
         #            )
         # )
# +
#   geom_jitter()

DwellTDeltaT_Scatter_Combined

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayBmb3IgV01BVEEgTWV0cm9idXMgRGF0YSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2sgZm9yIGFuYWx5c2lzIHVzaW5nIGRhdGEgb24gdGhlIERDIEJ1cyBTeXN0ZW0gKFdNQVRBIE1ldHJvYnVzKS4gIFRoZSBkYXRhIHdlcmUgb2J0YWluZWQgaGVyZToKCmh0dHBzOi8vcGxhbml0bWV0cm8uY29tLzIwMTYvMTEvMTYvZGF0YS1kb3dubG9hZC1tZXRyb2J1cy12ZWhpY2xlLWxvY2F0aW9uLWRhdGEvCgpDb250cm9sICsgQWx0ICsgU2hpZnQgKyBtID0gcmVuYW1lIGluIHNjb3BlCgpMb2FkIHRoZSBwYWNrYWdlcyB0byBiZSB1c2VkLgpgYGB7ciBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KCmxpYnJhcnkoInRpZHlyIikKbGlicmFyeSgicGx5ciIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgibWFncml0dHIiKQpsaWJyYXJ5KCJzdHJpbmdyIikKbGlicmFyeSgiZGF0YS50YWJsZSIpCmxpYnJhcnkoImx1YnJpZGF0ZSIpCmxpYnJhcnkoImdlb3NwaGVyZSIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJnZ3ZpcyIpCmxpYnJhcnkoInJib2tlaCIpCgpgYGAKCgpHZXQgdGhlIGRhdGEuCgpGaXJzdCBsZXQncyBjaGVjayB0aGUgd29ya2luZyBkaXJlY3RvcnkuCmBgYHtyfQoKZ2V0d2QoKQoKYGBgCgoKVGhlbiwgYWN0dWFsbHkgZ2V0IHRoZSBkYXRhLgpgYGB7ciBlY2hvID0gRkFMU0V9CgpzZXR3ZCgiL1VzZXJzL21kdHVyc2UvRGVza3RvcC9BbmFseXRpY3MvRENNZXRyb0J1cy9CdXMgQVZMIE9jdCAyMDE2IikKCmZvciAoaSBpbiAzOjcpewogIGFzc2lnbihwYXN0ZTAoIk9jdDAiLCBpLCAiUmF3IiksCiAgICAgICAgIHJlYWQuZGVsaW0ocGFzdGUwKCIyMDE2MTAwIiwgaSwgIk1ldHJvYnVzQVZMLnR4dCIpLAogICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICBuYS5zdHJpbmdzID0gTlVMTAogICAgICAgICAgICAgICAgICAgKQogICAgICAgICkKICAKICBtZXNzYWdlKCJPY3QwIiwgaSwgIlJhdyIpCiAKICBzdHIoZ2V0KHBhc3RlMCgiT2N0MCIsIGksICJSYXciKQogICAgICAgICApCiAgICAgKQogIH0KCmBgYAoKClB1dCB0aGUgZGFpbHkgZGF0YSB0b2dldGhlci4KYGBge3J9CgpBbGxEYXlzIDwtIGJpbmRfcm93cyhsaXN0KE9jdDAzUmF3LCBPY3QwNFJhdywgT2N0MDVSYXcsIE9jdDA2UmF3LCBPY3QwN1JhdyksCiAgICAgICAgICAgICAgICAgICAgIC5pZCA9IGMoImdyb3VwIikKICAgICAgICAgICAgICAgICAgICApCiMgZGltKEFsbERheXMpCnN0cihBbGxEYXlzKQoKYGBgCgoKRGVsZXRpbmcgb2xkIGRhdGEgZnJhbWVzLgpgYGB7cn0KCmZvciAoaSBpbiAzOjcpewogIHJtKGxpc3QgPSBscyhwYXR0ZXJuID0gcGFzdGUwKCJPY3QwIiwgaSwgIlJhdyIpCiAgICAgICAgICAgICAgKQogICAgKQogIAogIG1lc3NhZ2UoIkRlbGV0aW5nIE9jdDAiLCBpLCAiUmF3IikKICB9CgpgYGAKCgpVcGRhdGluZyB2YXJpYWJsZSB0eXBlcy4KClRoZW4sIHNvcnRpbmcgdGhlIGRhdGEgYW5kIGFkZGluZyBhIFJvd051bWJlciAodG8gYmUgdXNlZCBmb3IgaWRlbnRpZnlpbmcgcm93cyBsYXRlciBpbiB0aGUgYW5hbHlzZXMuKQpgYGB7cn0KCkFsbERheXMkZ3JvdXAgPC0gZmFjdG9yKEFsbERheXMkZ3JvdXApCkFsbERheXMkUm91dGVfRGlyZWN0aW9uIDwtIGZhY3RvcihBbGxEYXlzJFJvdXRlX0RpcmVjdGlvbikKQWxsRGF5cyRFdmVudF9UaW1lIDwtIGFzLlBPU0lYY3QoQWxsRGF5cyRFdmVudF9UaW1lLCBmb3JtYXQgPSAiJW0tJWQtJXkgJUk6JU06JVMgJXAiKQpBbGxEYXlzJERlcGFydHVyZV9UaW1lIDwtIGFzLlBPU0lYY3QoQWxsRGF5cyREZXBhcnR1cmVfVGltZSwgZm9ybWF0ID0gIiVtLSVkLSV5ICVJOiVNOiVTICVwIikKCnN0cihBbGxEYXlzKQoKCkFsbERheXNfU29ydGVkIDwtIGFycmFuZ2UoQWxsRGF5cywKICAgICAgICAgICAgICAgICAgICAgICAgICBCdXNfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZQogICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFJvd051bV9PRyA9IHJvd19udW1iZXIoKSAjIHRoaXMgaXMgdXNlZnVsIGluIGlkZW50aWZ5IHRoZSByb3cgbGF0ZXIgb24KICAgICAgICApCgpybShBbGxEYXlzKQpzdHIoQWxsRGF5c19Tb3J0ZWQpCgojIFZpZXcoaGVhZChBbGxEYXlzX1NvcnRlZCwgMTAwKSkKCmBgYAoKCkluc3BlY3RpbmcgdGhlIHZhbHVlcyBvZiBTdG9wX0lELCBhbmQgZmluZGluZyB0aGF0IGl0IGNhbiB0YWtlIHRoZSB2YWx1ZXMgIiIgKGJsYW5rKSBhbmQgIk5VTEwiLgpgYGB7cn0KClZpZXcoZ3JvdXBfYnkoQWxsRGF5c19Tb3J0ZWQsCiAgICAgICAgICAgICAgU3RvcF9JRAogICAgICAgICAgICAgKSAlPiUgCiAgICAgICBzdW1tYXJpc2UoCiAgICAgICAgIENudCA9IG4oKQogICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoU3RvcF9JRCkKICAgICkKClZpZXcoZmlsdGVyKEFsbERheXNfU29ydGVkLAogICAgICAgICAgICBpcy5uYShTdG9wX0lEKSB8CiAgICAgICAgICAgICAgU3RvcF9JRCA9PSAiIiB8CiAgICAgICAgICAgICAgU3RvcF9JRCA9PSAiTlVMTCIKICAgICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoU3RvcF9EZXNjKQogICAgKQoKYGBgCgoKQ3JlYXRpbmcgYSB0YWJsZSBvZiBkaXN0aW5jdCBTdG9wX0Rlc2MgdmFsdWVzIHdoZW4gU3RvcF9JRCBpcyAiIiAoYmxhbmspIG9yICJOVUxMIi4KYGBge3J9CgpTdG9wSURfTmV3IDwtIGZpbHRlcihBbGxEYXlzX1NvcnRlZCwKICAgICAgICAgICAgICAgICAgICAgaXMubmEoU3RvcF9JRCkgfAogICAgICAgICAgICAgICAgICAgICAgIFN0b3BfSUQgPT0gIiIgfAogICAgICAgICAgICAgICAgICAgICAgIFN0b3BfSUQgPT0gIk5VTEwiCiAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc2VsZWN0KFN0b3BfSUQsIFN0b3BfRGVzYykgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGFycmFuZ2UoU3RvcF9JRCwgU3RvcF9EZXNjKSAlPiUgCiAgbXV0YXRlKFN0b3BJRF9OZXcgPSAxOm5yb3coLikKICAgICAgICApCgpWaWV3KFN0b3BJRF9OZXcpCgpgYGAKCgpDcmVhdGluZyBhIGZ1bGwgdXBkYXRlZCB0YWJsZSBieSBmaWxsaW5nIGluIFN0b3BJRF9OZXcgZm9yIHdoZW4gU3RvcF9JRCBpcyAiIiAoYmxhbmspIG9yIE5VTEwuCmBgYHtyfQoKQWxsRGF5c19TdG9wSUROZXcgPC0gbGVmdF9qb2luKEFsbERheXNfU29ydGVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KFN0b3BJRF9OZXcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RvcF9EZXNjLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BJRF9OZXcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoIlN0b3BfRGVzYyIgPSAiU3RvcF9EZXNjIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFN0b3BJRF9DbGVhbiA9IGlmZWxzZShpcy5uYShTdG9wSURfTmV3KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdG9wSURfTmV3CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFN0b3BJRF9JbmRpY2F0b3IgPSBmYWN0b3IoaWZlbHNlKGlzLm5hKFN0b3BJRF9OZXcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSURfT0siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSURfQmFkIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICApCgpybShTdG9wSURfTmV3KQpybShBbGxEYXlzX1NvcnRlZCkKc3RyKEFsbERheXNfU3RvcElETmV3KQoKIyBWaWV3KHRhaWwoQWxsRGF5c19TdG9wSUROZXcsIDUwMCkpCiMgVmlldyhmaWx0ZXIoQWxsRGF5c19TdG9wSUROZXcsCiMgICAgICAgICAgICAgU3RvcF9EZXNjID09ICJNRVRST1dBWSBBTk5OT1VDRU1OVCBDT1JSIgojICAgICAgICAgICAgKQojICAgICApCgpgYGAKCgpGZWF0dXJlIGVuZ2luZWVyaW5nLgoKSW5zcGVjdGluZyBpbmNpZGVuY2VzIG9mIGNvbnNlY3V0aXZlIFN0b3BfSURzLiBUaGlzIGlzIGRvbmUgYmVjYXVzZSBpbnZlc3RpZ2F0aW9uIHNob3dlZCB0aGF0IG1hbnkgY29uc2V1dGl2ZSBldmVudHMgb2NjdXJyIGF0IHRoZSBzYW1lIFN0b3BfSUQsIGJ1dCB3aXRoIHZhcmlvdXMgRHdlbGxfVGltZXMsIE9kb21ldGVyX0Rpc3RhbmNlcywgZXRjLiAgQWxsIG9mIHdoaWNoIGFmZmVjdCBjYWxjdWxhdGlvbnMgYW5kIGFuYWx5c2VzLgoKQ3JlYXRlIGRhdGEgb24gdGhlIHJ1bnMgKGNvbnNlY3V0aXZlIFN0b3BfSURzKS4KYGBge3J9CgpTdG9wSURfUnVucyA8LSBybGUoQWxsRGF5c19TdG9wSUROZXckU3RvcElEX0NsZWFuKQoKU3RvcElEX1J1bnMkZW5kcyA8LSBjdW1zdW0oU3RvcElEX1J1bnMkbGVuZ3RocykKClN0b3BJRF9SdW5zJHN0YXJ0cyA8LSBpZmVsc2UoaXMubmEobGFnKFN0b3BJRF9SdW5zJGVuZHMpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFnKFN0b3BJRF9SdW5zJGVuZHMpICsgMQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKc3RyKFN0b3BJRF9SdW5zKQojIGNsYXNzKFN0b3BJRF9SdW5zKQojIAojIFN0b3BJRF9SdW5zX2RmIDwtIGRhdGEuZnJhbWUodW5jbGFzcyhTdG9wSURfUnVucykpCiMgc3RyKFN0b3BJRF9SdW5zX2RmKQojIGNsYXNzKFN0b3BJRF9SdW5zX2RmKQojIHJtKFN0b3BJRF9SdW5zX2RmKQoKYGBgCgoKVHJ5aW5nIHRvIGxpbmsgZGF0YSBvbiBSdW5zR3JvdXBzIHdpdGggdGhlIG9yaWdpbmFsIGRhdGEgKEFsbERheXNfU29ydGVkKS4gVGhlIGdvYWwgaXMgdG8gc2VsZWN0IG9ubHkgb25lIHJlY29yZCBwZXIgUnVuc0dyb3VwIC0gdGhhdCBiZWluZyB0aGUgcmVjb3JkIHdpdGggdGhlIGxvbmdlc3QgRHdlbGxfVGltZS4KCkkgYXR0ZW1wdGVkIHRoaXMgY29tcHV0YXRpb24gdXNpbmcgYm90aCBkYXRhLmZyYW1lcyAoZHBseXIpIGFuZCBkYXRhLnRhYmxlcyAoZGF0YS50YWJsZSkuIEhvd2V2ZXIsIHdpdGggMiw4MDksMDYyIHJvd3MgaW4gb25lIGRhdGFzZXQgYW5kIDMsMTE5LDQ0MyByb3dzIGluIHRoZSBvdGhlciBkYXRhc2V0LCB0aGUgY3VycmVudCBjb21wdXRhdGlvbiB0aW1lIGlzIG92ZXIgNSBkYXlzLi4uc28gSSdtIHRyeWluZyBhIGRpZmZlcmVudCBzdHJhdGVneSB0byBvbmx5IHNlbGVjdCB0aGUgZmlyc3QgcmVjb3JkIGluIGEgcnVuLgpgYGB7cn0KCiMgQ3JlYXRlIGEgUnVuc0dyb3VwIHZhcmlhYmxlIGZvciBlYWNoIHJ1bgojIFN0b3BJRF9SdW5zX2RmJFJ1bnNHcm91cCA8LSBwYXN0ZTAoImciLCBzZXEoMTpucm93KFN0b3BJRF9SdW5zX2RmKQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKIyAKIyBzdHIoU3RvcElEX1J1bnNfZGYpCiMgaGVhZChTdG9wSURfUnVuc19kZiwgMjUpCiMgdGFpbChTdG9wSURfUnVuc19kZiwgMjUpCiMgCiMgU3RvcElEX1J1bnNfZGYgPC0gU3RvcElEX1J1bnNfZGYgJT4lIAojICAgbXV0YXRlKFJvd051bSA9IHJvd19udW1iZXIoKQojICAgICAgICAgKQojIAojIHN0cihTdG9wSURfUnVuc19kZikKIyBoZWFkKFN0b3BJRF9SdW5zX2RmLCAyNSkKIyB0YWlsKFN0b3BJRF9SdW5zX2RmLCAyNSkKIyAKIyAKIyAjIENvbnZlcnRpbmcgdG8gZGF0YS50YWJsZXMgZm9yLCBob3BlZnVsbHksIGltcHJvdmVkIHBlcmZvcm1hbmNlIChzcGVlZCkgaW4gY29tcHV0YXRpb24KIyBTdG9wSURfUnVuc19kdCA8LSBkYXRhLnRhYmxlKFN0b3BJRF9SdW5zX2RmKQojIHNldGtleShTdG9wSURfUnVuc19kdCwgUm93TnVtKQojIHN0cihTdG9wSURfUnVuc19kdCkKIyAKIyBBbGxEYXlzX1NvcnRlZF9kdCA8LSBkYXRhLnRhYmxlKEFsbERheXNfU29ydGVkKQojIHNldGtleShBbGxEYXlzX1NvcnRlZF9kdCwgUm93TnVtX09HKQojIHN0cihBbGxEYXlzX1NvcnRlZF9kdCkKIyAjIHJtKEFsbERheXNfU29ydGVkX2R0KQojIAojIAojICMgQWN0dWFsIGxvb3AgdG8gcGVyZm9ybSB0aGUgY29tcHV0YXRpb25zIGFuZCBsaW5rIHRvIG9yaWdpbmFsIGRhdGEgKEFsbERheXNfU29ydGVkX2R0KQojIEdyb3VwRGF0YSA8LSBsaXN0KCkKIyBmb3IoaSBpbiAxOm5yb3coU3RvcElEX1J1bnNfZHQpCiMgICAgKSB7CiMgICBhc3NpZ24ocGFzdGUwKCJncm91cF8iLCBpKSwKIyAgICAgICAgICAgIFN0b3BJRF9SdW5zX2R0W1Jvd051bSA9PSBpLCBSdW5zR3JvdXBdCiMgICAgICAgICAgICkKIyAKIyAgICAgIyMjIyMgIFRoZSBjb2RlIGJlbG93IGlzIHRoZSBzYW1lIGNvZGUgYXMgYWJvdmUsIGJ1dCBkb25lIHdpdGggZHBseXIgICMjIyMjCiMgCiMgICAgICMgYXNzaWduKHBhc3RlMCgiZ3JvdXBfIiwgaSksCiMgICAjICAgICAgICBmaWx0ZXIoU3RvcElEX1J1bnNfZGYsCiMgICAjICAgICAgICAgICAgICAgUm93TnVtID09IGkKIyAgICMgICAgICAgICAgICAgICkgJT4lIAojICAgIyAgICAgICAgICBzZWxlY3QoUnVuc0dyb3VwKQojICAgIyAgICAgICApCiMgCiMgICBhc3NpZ24ocGFzdGUwKCJncm91cF8iLCBpLCAiX3N0YXJ0IiksCiMgICAgICAgICAgU3RvcElEX1J1bnNfZHRbUm93TnVtID09IGksIHN0YXJ0c10KIyAgICAgICAgICkKIyAKIyAgIGFzc2lnbihwYXN0ZTAoImdyb3VwXyIsIGksICJfZW5kIiksCiMgICAgICAgICAgU3RvcElEX1J1bnNfZHRbUm93TnVtID09IGksIGVuZHNdCiMgICAgICAgICApCiMgCiMgICBhc3NpZ24ocGFzdGUwKCJncm91cF8iLCBpLCAiX3Jvd3MiKSwKIyAgICAgICAgICBBbGxEYXlzX1NvcnRlZF9kdFtSb3dOdW1fT0cgPj0gYXMubnVtZXJpYyhnZXQocGFzdGUwKCJncm91cF8iLCBpLCAiX3N0YXJ0IikKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICYKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBSb3dOdW1fT0cgPD0gYXMubnVtZXJpYyhnZXQocGFzdGUwKCJncm91cF8iLCBpLCAiX2VuZCIpCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBSdW5zR3JvdXAgOj0gYXMuY2hhcmFjdGVyKGdldChwYXN0ZTAoImdyb3VwXyIsIGkpCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIF0KIyAKIyAgICAgIyMjIyMgIFRoZSBjb2RlIGJlbG93IGlzIHRoZSBzYW1lIGFzIHRoZSBjb2RlIGFib3ZlLCBidXQgZG9uZSB3aXRoIGRwbHlyICAjIyMjIwojIAojICAgICAgICAgICMgZmlsdGVyKEFsbERheXNfU29ydGVkLAojICAgICAgICAgICMgICAgICAgIGJldHdlZW4oUm93TnVtX09HLAojICAgICAgICAgICMgICAgICAgICAgICAgICAgYXMubnVtZXJpYyhnZXQocGFzdGUwKCJncm91cF8iLCBpLCAiX3N0YXJ0IikKIyAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICksCiMgICAgICAgICAgIyAgICAgICAgICAgICAgICBhcy5udW1lcmljKGdldChwYXN0ZTAoImdyb3VwXyIsIGksICJfZW5kIikKIyAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICkKIyAgICAgICAgICAjICAgICAgICAgICAgICAgKQojICAgICAgICAgICMgICAgICAgKSAlPiUgCiMgICAgICAgICAgIyAgIG11dGF0ZShSdW5zR3JvdXAgPSBhcy5jaGFyYWN0ZXIoZ2V0KHBhc3RlMCgiZ3JvdXBfIiwgaSkKIyAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKIyAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQojICAgICAgICAgICMgICAgICAgICkKIyAgICAgICAgICkKIyAKIyAgIEdyb3VwRGF0YVtbaV1dIDwtIGdldChwYXN0ZTAoImdyb3VwXyIsIGksICJfcm93cyIpKQojIAojICAgbWVzc2FnZSgiUHJvY2Vzc2luZyBHcm91cCAiLCBpLCAiIG9mIDIsODA5LDA2MiIpCiMgfQojIAojIAojIEdyb3VwRGF0YV9kZiA8LSByYmluZC5maWxsKEdyb3VwRGF0YSkKIyBzdHIoR3JvdXBEYXRhX2RmKQojIGhlYWQoR3JvdXBEYXRhX2RmKQojIHRhaWwoR3JvdXBEYXRhX2RmKQojICMgcm0oR3JvdXBEYXRhX2RmKQojIAojIAojIGdyb3VwXzEKIyBncm91cF8xX3N0YXJ0CiMgZ3JvdXBfMV9lbmQKIyBncm91cF8xX3Jvd3MKIyBncm91cF8yX3Jvd3MKIyBncm91cF8zX3Jvd3MKIyBncm91cF81MF9yb3dzCiMgc3RyKGdyb3VwXzUwX3Jvd3MpCiMgZ3JvdXBfMjgwOTA2Ml9yb3dzCiMgR3JvdXBEYXRhW1sxXV0KIyBHcm91cERhdGFbWzUwXV0KIyAKIyAKIyAjIyMjIyAgVGVzdGluZyBBcmVhIChCZWxvdykgICMjIyMjCiMgIyMjIyMgIFRlc3RpbmcgQXJlYSAoQmVsb3cpICAjIyMjIwojICMjIyMjICBUZXN0aW5nIEFyZWEgKEJlbG93KSAgIyMjIyMKIyAKIyAjIGhlYWQoU3RvcElEX1J1bnMkc3RhcnRzLCAyMCkKIyAjIGhlYWQoQWxsRGF5c19OZXdPcmRlciRTdG9wX0lELCAyMCkKIyAjIAojICMgCiMgIyBkYXQgPC0gYXMuZGF0YS5mcmFtZShjKDEsMSw3LDcsNyw5LDYsOCwyLDIsMiwxLDEsMSwxLDEpKQojICMgY29sbmFtZXMoZGF0KVsxXSA8LSAiZGF0IgojICMgciA8LSBybGUoZGF0JGRhdCkKIyAjIGRhdCRydW4gPC0gcmVwKHIkbGVuZ3RocywgciRsZW5ndGhzKQojICMgZGF0JHJ1bkxhZyA8LSBsYWcoZGF0JHJ1bikKIyAjIGRhdCRjb25kIDwtIHJlcChyJHZhbHVlcywgciRsZW5ndGhzKQojICMgZGF0CiMgIyBWaWV3KGRhdCkKCmBgYAoKCldoZW4gY29uc2VjdXRpdmUgU3RvcF9JRCBvY2N1cnJzLCBvbmx5IHRha2UgdGhlIGZpcnN0IG9jY3VycmVuY2UuIFRoaXMgaXMgZG9uZSBiZWNhdXNlIHRoZSBjb21wdXRhdGlvbiB0aW1lIHRvIHNlbGVjdCBvbmx5IHRoZSByZWNvcmQgd2l0aCB0aGUgbG9uZ2VzdCBEd2VsbF9UaW1lIGZvciBlYWNoIHJ1biB3YXMgdG9vIGxvbmcgKG92ZXIgNSBkYXlzKS4KClRoaXMgaXMgcHJvYmFibHkgbGVzcyB0aGFuIGlkZWFsIHdpdGggcmVnYXJkcyB0byBEd2VsbF9UaW1lLCBidXQgc2hvdWxkIG5vdCBtYWtlIG11Y2ggZGlmZmVyZW5jZSBmb3IgY2FsY3VsYXRpb25zIG9mIHRyYXZlbCB0aW1lLCBzcGVlZCwgZXRjLgpgYGB7cn0KCkFsbERheXNfRmlyc3RTdG9wSUQgPC0gQWxsRGF5c19TdG9wSUROZXdbU3RvcElEX1J1bnMkc3RhcnRzLCBdCgpkaW0oQWxsRGF5c19TdG9wSUROZXcpCmRpbShBbGxEYXlzX0ZpcnN0U3RvcElEKQoKbnJvdyhBbGxEYXlzX1N0b3BJRE5ldykgLSBucm93KEFsbERheXNfRmlyc3RTdG9wSUQpCgpybShBbGxEYXlzX1N0b3BJRE5ldykKcm0oU3RvcElEX1J1bnMpCnN0cihBbGxEYXlzX0ZpcnN0U3RvcElEKQoKYGBgCgoKRmVhdHVyZSBlbmdpbmVlcmluZy4KCkNyZWF0aW5nIG5ldyB2YXJpYWJsZXMuCmBgYHtyfQoKQWxsRGF5c19BZGRWYXJzIDwtIG11dGF0ZShBbGxEYXlzX0ZpcnN0U3RvcElELAogICAgICAgICAgICAgICAgICAgICAgICAgIE9kb21ldGVyX0Rpc3RhbmNlX01pID0gT2RvbWV0ZXJfRGlzdGFuY2UgLyA1MjgwLCAjNSwyODAgZmVldCBpbiAxIG1pbGUKICAgICAgICAgICAgICAgICAgICAgICAgICBEd2VsbF9UaW1lMiA9IGFzLm51bWVyaWMoRGVwYXJ0dXJlX1RpbWUgLSBFdmVudF9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX1lyID0gYXMuaW50ZWdlcih5ZWFyKEV2ZW50X1RpbWUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX010aCA9IGFzLmludGVnZXIobW9udGgoRXZlbnRfVGltZSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfRGF0ZSA9IGRheShFdmVudF9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0RheSA9IHdkYXkoRXZlbnRfVGltZSwgbGFiZWwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyID0gaG91cihFdmVudF9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX01pbiA9IG1pbnV0ZShFdmVudF9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyR3JvdXAgPSBmYWN0b3IoaWZlbHNlKEV2ZW50X1RpbWVfSHIgPCAzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMF8yIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEV2ZW50X1RpbWVfSHIgPCA2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwM181IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEV2ZW50X1RpbWVfSHIgPCA5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwNl84IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEV2ZW50X1RpbWVfSHIgPCAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcm91cDlfMTEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRXZlbnRfVGltZV9IciA8IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMTJfMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRXZlbnRfVGltZV9IciA8IDE4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMTVfMTciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRXZlbnRfVGltZV9IciA8IDIxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMThfMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRXZlbnRfVGltZV9IciA8IDI0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMjFfMjMiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpKSkpKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJHcm91cDBfMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwM181IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR3JvdXA2XzgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcm91cDlfMTEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcm91cDEyXzE0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR3JvdXAxNV8xNyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMThfMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcm91cDIxXzIzIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJlZCA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICApCgpybShBbGxEYXlzX0ZpcnN0U3RvcElEKQpzdHIoQWxsRGF5c19BZGRWYXJzKQoKCiMgZ3JvdXBfYnkoQWxsRGF5c19BZGRWYXJzLAojICAgICAgICAgIEV2ZW50X1RpbWVfSHJHcm91cAojICAgICAgICAgKSAlPiUgCiMgICBzdW1tYXJpc2UoQ250cyA9IG4oKQojICAgICAgICAgICAgKQoKCiMgVmlldyhoZWFkKGZpbHRlcihBbGxEYXlzX0FkZFZhcnMsCiMgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyID09IDAKIyAgICAgICAgICAgICAgICAgKSwKIyAgICAgICAgICAgNTAKIyAgICAgICAgICApCiMgICAgICkKCiMgVmlldyhoZWFkKEFsbERheXNfQWRkVmFycywgNTApKQoKYGBgCgoKPCEtLSBGdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgdGhlIGRpc3RhbmNlIHRyYXZlbGVkIGJhc2VkIG9uIHRoZSBIYXZlcnNpbmUgZm9ybXVsYS4gIE9yaWdpbmFsIGNvZGUgZnJvbTogaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vZ3JlYXQtY2lyY2xlLWRpc3RhbmNlLWNhbGN1bGF0aW9ucy1pbi1yLyAtLT4KPCEtLSBgYGB7cn0gLS0+Cgo8IS0tIGdjZC5oZiA8LSBmdW5jdGlvbihsb25nMSwgbGF0MSwgbG9uZzIsIGxhdDIpIHsgLS0+CjwhLS0gICBSIDwtIDYzNzEgIyBFYXJ0aCBtZWFuIHJhZGl1cyBba21dIC0tPgo8IS0tICAgZGVsdGEubG9uZyA8LSAobG9uZzIgLSBsb25nMSkgLS0+CjwhLS0gICBkZWx0YS5sYXQgPC0gKGxhdDIgLSBsYXQxKSAtLT4KPCEtLSAgIGEgPC0gc2luKGRlbHRhLmxhdC8yKV4yICsgY29zKGxhdDEpICogY29zKGxhdDIpICogc2luKGRlbHRhLmxvbmcvMileMiAtLT4KPCEtLSAgIGMgPC0gMiAqIGFzaW4obWluKDEsc3FydChhKSkpIC0tPgo8IS0tICAgZCA9IFIgKiBjICogMC42MjEzNzEgIyAxIGttID0gMC42MjEzNzEgbWlsZXMgLS0+CjwhLS0gICByZXR1cm4oZCkgIyBEaXN0YW5jZSBpbiBtaWxlcyAtLT4KPCEtLSB9IC0tPgoKPCEtLSBgYGAgLS0+CgoKRmVhdHVyZSBlbmdpbmVlcmluZy4KCkNyZWF0aW5nIG1vcmUgdmFyaWFibGVzLiBDcmVhdGluZyBhIEJ1c0V2ZW50IHJvdyBudW1iZXIgZm9yIGZ1dHVyZSBpZGVudGlmaWNhdGlvbiBwdXJwb3Nlcy4gVGhlbiwgY3JlYXRpbmcgdmFyaW91cyB2YXJpYWJsZXMgdG8gYW5hbHl6ZSBkaXN0YW5jZSB0cmF2ZWxlZCBhbmQgc3BlZWQuCmBgYHtyfQoKQWxsRGF5c19CdXNEYXkgPC0gZ3JvdXBfYnkoQWxsRGF5c19BZGRWYXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICBCdXNfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfRGF0ZQogICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIG11dGF0ZShCdXNEYXlfRXZlbnROdW0gPSByb3dfbnVtYmVyKCksICAjIHVzZWQgdG8gaWRlbnRpZnkgQnVzIG1vdmVtZW50cyBvbiBhIHBhcnRpY3VsYXIgZGF0ZQogICAgICAgICAKICAgICAgICAgT2RvbWV0ZXJfRGlzdGFuY2VfTGFnMSA9IGxhZyhPZG9tZXRlcl9EaXN0YW5jZSksCiAgICAgICAgIAogICAgICAgICBMYXRpdHVkZV9MMSA9IGxhZyhMYXRpdHVkZSksCiAgICAgICAgIExvbmdpdHVkZV9MMSA9IGxhZyhMb25naXR1ZGUpLAogICAgICAgICAjIExhdF9SYWRpYW4gPSBMYXRpdHVkZSpwaS8xODAsCiAgICAgICAgICMgTG9uZ19SYWRpYW4gPSBMb25naXR1ZGUqcGkvMTgwLAogICAgICAgICAjIExhdF9SYWRpYW5fTDEgPSBsYWcoTGF0X1JhZGlhbiksCiAgICAgICAgICMgTG9uZ19SYWRpYW5fTDEgPSBsYWcoTG9uZ19SYWRpYW4pLAogICAgICAgICAKICAgICAgICAgIyBhY2NvdW50aW5nIGZvciBwb3RlbnRpYWwgbmVnYXRpdmUgZGlzdGFuY2VzCiAgICAgICAgIFRyYXZlbERpc3RhbmNlX0Z0ID0gaWZlbHNlKE9kb21ldGVyX0Rpc3RhbmNlID4gT2RvbWV0ZXJfRGlzdGFuY2VfTGFnMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT2RvbWV0ZXJfRGlzdGFuY2UgLSBPZG9tZXRlcl9EaXN0YW5jZV9MYWcxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pID0gVHJhdmVsRGlzdGFuY2VfRnQgLyA1MjgwLCAjNSwyODAgZmVldCBpbiAxIG1pbGUKICAgICAgICAgCiAgICAgICAgICMgVHJhdmVsRGlzdGFuY2VfTWkyID0gZ2NkLmhmKGxvbmcxID0gTG9uZ19SYWRpYW5fTDEsCiAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhdDEgPSBMYXRfUmFkaWFuX0wxLAogICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb25nMiA9IExvbmdfUmFkaWFuLAogICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXQyID0gTGF0X1JhZGlhbgogICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIAogICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaWZlbHNlKChpcy5uYShMb25naXR1ZGVfTDEpIHwgaXMubmEoTGF0aXR1ZGVfTDEpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0SGF2ZXJzaW5lKGNiaW5kKExvbmdpdHVkZV9MMSwgTGF0aXR1ZGVfTDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNiaW5kKExvbmdpdHVkZSwgTGF0aXR1ZGUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICogMC4wMDA2MjEzNzEsICMgMC4wMDA2MjEzNzEgbWlsZXMgPSAxIG1ldGVyCiAgICAgICAgIAogICAgICAgICAjIGFjY291bnRpbmcgZm9yIHBvdGVudGlhbCBuZWdhdGl2ZSB0aW1lcwogICAgICAgICBUcmF2ZWxUaW1lX1NlYyA9IGFzLm51bWVyaWMoaWZlbHNlKEV2ZW50X1RpbWUgPiBsYWcoRGVwYXJ0dXJlX1RpbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWUgLSBsYWcoRGVwYXJ0dXJlX1RpbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFRyYXZlbFRpbWVfSHIgPSBUcmF2ZWxUaW1lX1NlYyAvIDM2MDAsICMgMyw2MDAgc2Vjb25kcyBpbiAxIGhvdXIKICAgICAgICAgCiAgICAgICAgICMgYWNjb3VudGluZyBmb3IgcG90ZW50aWFsIG5lZ2F0aXZlIG9yIHplcm8gdHJhdmVsIHRpbWVzCiAgICAgICAgIFNwZWVkQXZnX01waCA9IGlmZWxzZShUcmF2ZWxUaW1lX0hyID4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pIC8gVHJhdmVsVGltZV9IciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIAogICAgICAgICBTdGFydF9JRCA9IGxhZyhTdG9wSURfQ2xlYW4pLAogICAgICAgICBTdGFydF9EZXNjID0gbGFnKFN0b3BfRGVzYyksCiAgICAgICAgIFN0YXJ0U3RvcF9JRCA9IGlmZWxzZShpcy5uYShTdGFydF9JRCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiTlVMTCIsIFN0b3BJRF9DbGVhbiwgc2VwID0gIi0tIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShTdGFydF9JRCwgU3RvcElEX0NsZWFuLCBzZXAgPSAiLS0iKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpCgoKcm0oQWxsRGF5c19BZGRWYXJzKQpzdHIoQWxsRGF5c19CdXNEYXkpCgojIHN1bW1hcnkoQWxsRGF5c19CdXNEYXkpCgojIFZpZXcodGFpbChBbGxEYXlzX0J1c0RheSwgNTApKQoKYGBgCgoKSW5zcGVjdGluZyBmb3IgaXNzdWVzIHdpdGggU3RhcnRTdG9wX0lEICh3aGVyZSB0aGUgdmFsdWUgaXMgZWl0aGVyIE5BIG9yIGNvbnRhaW5zIE5VTEwpLiBUaGV5IE9OTFkgZXhpc3Qgd2hlbiBCdXNEYXlfRXZlbnROdW0gPSAxICh3aGljaCBpcyBieSBkZXNpZ24pLiBTbyBldmVyeXRoaW5nIGxvb2tzIE9LLgpgYGB7cn0KClZpZXcoZ3JvdXBfYnkoQWxsRGF5c19CdXNEYXksCiAgICAgICAgICAgICAgU3RhcnRTdG9wX0lECiAgICAgICAgICAgICApICU+JSAKICAgICAgIHN1bW1hcmlzZSgKICAgICAgICAgQ250ID0gbigpCiAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoZGVzYyhDbnQpCiAgICAgICAgICAgICAgKQogICAgKQoKVmlldyhmaWx0ZXIoQWxsRGF5c19CdXNEYXksCiAgICAgICAgICAgIChpcy5uYShTdGFydFN0b3BfSUQpIHwKICAgICAgICAgICAgICBzdHJfZGV0ZWN0KFN0YXJ0U3RvcF9JRCwgIk5VTEwiKQogICAgICAgICAgICApICYKICAgICAgICAgICAgICBCdXNEYXlfRXZlbnROdW0gIT0gMQogICAgICAgICAgICkKICAgICkKCmBgYAoKClN0YXRzIGZvciBTdGFydFN0b3BfSUQuCmBgYHtyfQoKUXVhbnRpbGVzX1NTX2R0IDwtIGdyb3VwX2J5KEFsbERheXNfQnVzRGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RhcnRTdG9wX0lECiAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIG11dGF0ZShURF9NaV9TU19xNSA9IHF1YW50aWxlKHggPSBUcmF2ZWxEaXN0YW5jZV9NaSwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBURF9NaV9TU19xOTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsRGlzdGFuY2VfTWksIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfU2VjX1NTX3E1ID0gcXVhbnRpbGUoeCA9IFRyYXZlbFRpbWVfU2VjLCBwcm9icyA9IDAuMDUsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX1NlY19TU19xOTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9TZWMsIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfU1NfcTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9IciwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9Icl9TU19xOTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9IciwgcHJvYnMgPSAwLjk1LCBuYS5ybSA9IFRSVUUpCiAgICAgICAgKSAlPiUgCiAgZGF0YS50YWJsZSgpCgoKU3RhdHNfU3RTdCA8LSBncm91cF9ieShRdWFudGlsZXNfU1NfZHQsCiAgICAgICAgICAgICAgICAgICAgICAgU3RhcnRTdG9wX0lECiAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBtdXRhdGUoVERfTWlfU1NfTWVhbiA9IG1lYW4oVHJhdmVsRGlzdGFuY2VfTWksIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFREX01pX1NTX01lYW5fRiA9IG1lYW4oVHJhdmVsRGlzdGFuY2VfTWlbVERfTWlfU1NfcTUgPD0gVHJhdmVsRGlzdGFuY2VfTWkgJiBUcmF2ZWxEaXN0YW5jZV9NaSA8PSBURF9NaV9TU19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVERfTWlfU1NfTWVkID0gbWVkaWFuKFRyYXZlbERpc3RhbmNlX01pLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBURF9NaV9TU19NZWRfRiA9IG1lZGlhbihUcmF2ZWxEaXN0YW5jZV9NaVtURF9NaV9TU19xNSA8PSBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pIDw9IFREX01pX1NTX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFREX01pX1NTX0NudCA9IHN1bSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFREX01pX1NTX0NudF9GID0gc3VtKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaVtURF9NaV9TU19xNSA8PSBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pIDw9IFREX01pX1NTX3E5NV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIAogICAgICAgICBUVF9TZWNfU1NfTWVhbiA9IG1lYW4oVHJhdmVsVGltZV9TZWMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX1NlY19TU19NZWFuX0YgPSBtZWFuKFRyYXZlbFRpbWVfU2VjW1RUX1NlY19TU19xNSA8PSBUcmF2ZWxUaW1lX1NlYyAmIFRyYXZlbFRpbWVfU2VjIDw9IFRUX1NlY19TU19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9TZWNfU1NfTWVkID0gbWVkaWFuKFRyYXZlbFRpbWVfU2VjLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9TZWNfU1NfTWVkX0YgPSBtZWRpYW4oVHJhdmVsVGltZV9TZWNbVFRfU2VjX1NTX3E1IDw9IFRyYXZlbFRpbWVfU2VjICYgVHJhdmVsVGltZV9TZWMgPD0gVFRfU2VjX1NTX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVFRfU2VjX1NTX0NudCA9IHN1bSghaXMubmEoVHJhdmVsVGltZV9TZWMpKSwKICAgICAgICAgVFRfU2VjX1NTX0NudF9GID0gc3VtKCFpcy5uYShUcmF2ZWxUaW1lX1NlY1tUVF9TZWNfU1NfcTUgPD0gVHJhdmVsVGltZV9TZWMgJiBUcmF2ZWxUaW1lX1NlYyA8PSBUVF9TZWNfU1NfcTk1XQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAoKICAgICAgICAgVFRfSHJfU1NfTWVhbiA9IG1lYW4oVHJhdmVsVGltZV9IciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfU1NfTWVhbl9GID0gbWVhbihUcmF2ZWxUaW1lX0hyW1RUX0hyX1NTX3E1IDw9IFRyYXZlbFRpbWVfSHIgJiBUcmF2ZWxUaW1lX0hyIDw9IFRUX0hyX1NTX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9Icl9TU19NZWQgPSBtZWRpYW4oVHJhdmVsVGltZV9IciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfU1NfTWVkX0YgPSBtZWRpYW4oVHJhdmVsVGltZV9IcltUVF9Icl9TU19xNSA8PSBUcmF2ZWxUaW1lX0hyICYgVHJhdmVsVGltZV9IciA8PSBUVF9Icl9TU19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9Icl9TU19DbnQgPSBzdW0oIWlzLm5hKFRyYXZlbFRpbWVfSHIpKSwKICAgICAgICAgVFRfSHJfU1NfQ250X0YgPSBzdW0oIWlzLm5hKFRyYXZlbFRpbWVfSHJbVFRfSHJfU1NfcTUgPD0gVHJhdmVsVGltZV9IciAmIFRyYXZlbFRpbWVfSHIgPD0gVFRfSHJfU1NfcTk1XQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICkgJT4lIAogIGRhdGEuZnJhbWUoKQoKc3RyKFN0YXRzX1N0U3QpClZpZXcoaGVhZChTdGF0c19TdFN0LCA1MCkpCgpgYGAKCgpTdGF0cyBmb3IgU3RhcnRTdG9wX0lEIHdpdGggRXZlbnRfVGltZV9Ickdyb3VwLgpgYGB7cn0KClF1YW50aWxlc19TU0hHX2R0IDwtIGdyb3VwX2J5KFN0YXRzX1N0U3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0YXJ0U3RvcF9JRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9Ickdyb3VwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFREX01pX1NTSEdfcTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsRGlzdGFuY2VfTWksIHByb2JzID0gMC4wNSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVERfTWlfU1NIR19xOTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsRGlzdGFuY2VfTWksIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfU2VjX1NTSEdfcTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9TZWMsIHByb2JzID0gMC4wNSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfU2VjX1NTSEdfcTk1ID0gcXVhbnRpbGUoeCA9IFRyYXZlbFRpbWVfU2VjLCBwcm9icyA9IDAuOTUsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX0hyX1NTSEdfcTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9IciwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9Icl9TU0hHX3E5NSA9IHF1YW50aWxlKHggPSBUcmF2ZWxUaW1lX0hyLCBwcm9icyA9IDAuOTUsIG5hLnJtID0gVFJVRSkKICAgICAgICApICU+JSAKICBkYXRhLnRhYmxlKCkKCgpTdGF0c19TdFN0X0hyR3JwIDwtIGdyb3VwX2J5KFF1YW50aWxlc19TU0hHX2R0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0YXJ0U3RvcF9JRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyR3JvdXAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIG11dGF0ZShURF9NaV9TU0hHX01lYW4gPSBtZWFuKFRyYXZlbERpc3RhbmNlX01pLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBURF9NaV9TU0hHX01lYW5fRiA9IG1lYW4oVHJhdmVsRGlzdGFuY2VfTWlbVERfTWlfU1NIR19xNSA8PSBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pIDw9IFREX01pX1NTSEdfcTk1XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBURF9NaV9TU0hHX01lZCA9IG1lZGlhbihUcmF2ZWxEaXN0YW5jZV9NaSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVERfTWlfU1NIR19NZWRfRiA9IG1lZGlhbihUcmF2ZWxEaXN0YW5jZV9NaVtURF9NaV9TU0hHX3E1IDw9IFRyYXZlbERpc3RhbmNlX01pICYgVHJhdmVsRGlzdGFuY2VfTWkgPD0gVERfTWlfU1NIR19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVERfTWlfU1NIR19DbnQgPSBzdW0oIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFREX01pX1NTSEdfQ250X0YgPSBzdW0oIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pW1REX01pX1NTSEdfcTUgPD0gVHJhdmVsRGlzdGFuY2VfTWkgJiBUcmF2ZWxEaXN0YW5jZV9NaSA8PSBURF9NaV9TU0hHX3E5NV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAKICAgICAgICAgVFRfU2VjX1NTSEdfTWVhbiA9IG1lYW4oVHJhdmVsVGltZV9TZWMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX1NlY19TU0hHX01lYW5fRiA9IG1lYW4oVHJhdmVsVGltZV9TZWNbVFRfU2VjX1NTSEdfcTUgPD0gVHJhdmVsVGltZV9TZWMgJiBUcmF2ZWxUaW1lX1NlYyA8PSBUVF9TZWNfU1NIR19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVFRfU2VjX1NTSEdfTWVkID0gbWVkaWFuKFRyYXZlbFRpbWVfU2VjLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9TZWNfU1NIR19NZWRfRiA9IG1lZGlhbihUcmF2ZWxUaW1lX1NlY1tUVF9TZWNfU1NIR19xNSA8PSBUcmF2ZWxUaW1lX1NlYyAmIFRyYXZlbFRpbWVfU2VjIDw9IFRUX1NlY19TU0hHX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFRUX1NlY19TU0hHX0NudCA9IHN1bSghaXMubmEoVHJhdmVsVGltZV9TZWMpKSwKICAgICAgICAgVFRfU2VjX1NTSEdfQ250X0YgPSBzdW0oIWlzLm5hKFRyYXZlbFRpbWVfU2VjW1RUX1NlY19TU0hHX3E1IDw9IFRyYXZlbFRpbWVfU2VjICYgVHJhdmVsVGltZV9TZWMgPD0gVFRfU2VjX1NTSEdfcTk1XQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKCiAgICAgICAgIFRUX0hyX1NTSEdfTWVhbiA9IG1lYW4oVHJhdmVsVGltZV9IciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfU1NIR19NZWFuX0YgPSBtZWFuKFRyYXZlbFRpbWVfSHJbVFRfSHJfU1NIR19xNSA8PSBUcmF2ZWxUaW1lX0hyICYgVHJhdmVsVGltZV9IciA8PSBUVF9Icl9TU0hHX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVFRfSHJfU1NIR19NZWQgPSBtZWRpYW4oVHJhdmVsVGltZV9IciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfU1NIR19NZWRfRiA9IG1lZGlhbihUcmF2ZWxUaW1lX0hyW1RUX0hyX1NTSEdfcTUgPD0gVHJhdmVsVGltZV9IciAmIFRyYXZlbFRpbWVfSHIgPD0gVFRfSHJfU1NIR19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVFRfSHJfU1NIR19DbnQgPSBzdW0oIWlzLm5hKFRyYXZlbFRpbWVfSHIpKSwKICAgICAgICAgVFRfSHJfU1NIR19DbnRfRiA9IHN1bSghaXMubmEoVHJhdmVsVGltZV9IcltUVF9Icl9TU0hHX3E1IDw9IFRyYXZlbFRpbWVfSHIgJiBUcmF2ZWxUaW1lX0hyIDw9IFRUX0hyX1NTSEdfcTk1XQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICApICU+JSAKICBkYXRhLmZyYW1lKCkKCnN0cihTdGF0c19TdFN0X0hyR3JwKQojIFZpZXcoaGVhZChTdGF0c19TdFN0X0hyR3JwLCA1MCkpCgpgYGAKCgpGZWF0dXJlIGVuZ2luZWVyaW5nLgoKQ3JlYXRpbmcgYSBCdXNFdmVudFJvdXRlIHJvdyBudW1iZXIsIGFuZCBhIFJvdXRlQWx0X0xhZzEgaW5kaWNhdG9yIGZvciBmdXR1cmUgaWRlbnRpZmljYXRpb24gcHVycG9zZXMuIApgYGB7cn0KCnJtKFF1YW50aWxlc19TU19kdCkKcm0oQWxsRGF5c19CdXNEYXkpCnJtKFF1YW50aWxlc19TU0hHX2R0KQpybShTdGF0c19TdFN0KQoKQWxsRGF5c19CdXNEYXlSb3V0ZSA8LSBncm91cF9ieShTdGF0c19TdFN0X0hyR3JwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJ1c19JRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0RhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUm91dGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIG11dGF0ZShSb3V0ZUFsdF9MYWcxID0gbGFnKFJvdXRlQWx0KSAgIyB1c2VkIGluIGZ1dHVyZSBhbmFseXNlcyB0byBpZGVudGlmeSBSb3V0ZSBjaGFuZ2VzCiAgICAgICAgICMgT2RvbWV0ZXJfRGlzdGFuY2VfTGFnMSA9IGxhZyhPZG9tZXRlcl9EaXN0YW5jZSksCiAgICAgICAgICMgCiAgICAgICAgICMgIyBhY2NvdW50aW5nIGZvciBwb3RlbnRpYWwgbmVnYXRpdmUgZGlzdGFuY2VzCiAgICAgICAgICMgVHJhdmVsRGlzdGFuY2VfRnQgPSBpZmVsc2UoT2RvbWV0ZXJfRGlzdGFuY2UgPj0gT2RvbWV0ZXJfRGlzdGFuY2VfTGFnMSwKICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBPZG9tZXRlcl9EaXN0YW5jZSAtIE9kb21ldGVyX0Rpc3RhbmNlX0xhZzEsCiAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEKICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICMgVHJhdmVsRGlzdGFuY2VfTWkgPSBUcmF2ZWxEaXN0YW5jZV9GdCAvIDUyODAsICM1LDI4MCBmZWV0IGluIDEgbWlsZQogICAgICAgICAjIAogICAgICAgICAjICMgYWNjb3VudGluZyBmb3IgcG90ZW50aWFsIG5lZ2F0aXZlIHRpbWVzCiAgICAgICAgICMgVHJhdmVsVGltZV9TZWMgPSBhcy5udW1lcmljKGlmZWxzZShFdmVudF9UaW1lID49IGxhZyhEZXBhcnR1cmVfVGltZSksCiAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lIC0gbGFnKERlcGFydHVyZV9UaW1lKSwKICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BCiAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAjIFRyYXZlbFRpbWVfSHIgPSBUcmF2ZWxUaW1lX1NlYyAvIDM2MDAsICMgMyw2MDAgc2Vjb25kcyBpbiAxIGhvdXIKICAgICAgICAgIyAKICAgICAgICAgIyAjIGFjY291bnRpbmcgZm9yIHBvdGVudGlhbCBuZWdhdGl2ZSBvciB6ZXJvIHRyYXZlbCB0aW1lcwogICAgICAgICAjIFNwZWVkQXZnX01waCA9IGlmZWxzZShUcmF2ZWxUaW1lX0hyID4gMCwKICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWkgLyBUcmF2ZWxUaW1lX0hyLAogICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICBOQQogICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICApICU+JSAKICBkYXRhLmZyYW1lKCkKCnN0cihBbGxEYXlzX0J1c0RheVJvdXRlKQoKYGBgCgoKRmVhdHVyZSBlbmdpbmVlcmluZy4KCkNhbGN1bGF0aW5nIGEgdmFyaWFibGUgdG8ga25vdyBpZiB0aGUgUm91dGVBbHQgY2hhbmdlZC4gQ291bGQgYmUgdXNlZnVsIGluIGhlbHBpbmcgaWRlbnRpZnlpbmcgd2VpcmRuZXNzIGluIGNhbGN1bGF0ZWQgZGlzdGFuY2VzIGFuZCBzcGVlZHMuCmBgYHtyfQoKcm0oU3RhdHNfU3RTdF9IckdycCkKCkFsbERheXNfRGlyQ2hhbmdlIDwtIEFsbERheXNfQnVzRGF5Um91dGUgJT4lIAogIG11dGF0ZShEaXJDaGFuZ2UgPSBpZmVsc2UoUm91dGVBbHQgPT0gUm91dGVBbHRfTGFnMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTYW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaGFuZ2UiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIERpckNoYW5nZTIgPSBmYWN0b3IoaWZlbHNlKGlzLm5hKERpckNoYW5nZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaGFuZ2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaXJDaGFuZ2UKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgKQoKc3RyKEFsbERheXNfRGlyQ2hhbmdlKQoKYGBgCgoKUmUtb3JkZXJpbmcgdGhlIHZhcmlhYmxlcyB0byBlYXNlIHdpdGggY29tcHJlaGVuc2lvbi4KYGBge3J9CgpybShBbGxEYXlzX0J1c0RheVJvdXRlKQoKQWxsRGF5c19OZXdPcmRlciA8LSAgc2VsZWN0KEFsbERheXNfRGlyQ2hhbmdlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgUm93TnVtX09HLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdGFydFN0b3BfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBCdXNEYXlfRXZlbnROdW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBCdXNfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBSb3V0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJvdXRlQWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBSb3V0ZUFsdF9MYWcxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRGlyQ2hhbmdlMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJvdXRlX0RpcmVjdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BfU2VxdWVuY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdGFydF9JRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0YXJ0X0Rlc2MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFN0b3BfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdG9wSURfQ2xlYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdG9wSURfSW5kaWNhdG9yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RvcF9EZXNjLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X0Rlc2NyaXB0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9ZciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfTXRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9EYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9EYXksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9Ickdyb3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9NaW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVwYXJ0dXJlX1RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEd2VsbF9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRHdlbGxfVGltZTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWx0YV9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF0aXR1ZGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb25naXR1ZGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBIZWFkaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgT2RvbWV0ZXJfRGlzdGFuY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBPZG9tZXRlcl9EaXN0YW5jZV9MYWcxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgT2RvbWV0ZXJfRGlzdGFuY2VfTWksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9GdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTX3E1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfcTk1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NIR19xNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTSEdfcTk1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfTWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTX01lYW5fRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTSEdfTWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTSEdfTWVhbl9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfTWVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfTWVkX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU0hHX01lZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTSEdfTWVkX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19DbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19DbnRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTSEdfQ250LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NIR19DbnRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTX3E1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTX3E5NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU0hHX3E1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTSEdfcTk1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTX01lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfTWVhbl9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTSEdfTWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU0hHX01lYW5fRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU19NZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfTWVkX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NIR19NZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NIR19NZWRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU19DbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfQ250X0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NIR19DbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NIR19DbnRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfSHIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU19xNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTX3E5NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTSEdfcTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU0hHX3E5NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTX01lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU19NZWFuX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU0hHX01lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU0hHX01lYW5fRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTX01lZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTX01lZF9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfU1NIR19NZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU0hHX01lZF9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfU1NfQ250LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfU1NfQ250X0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU0hHX0NudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTSEdfQ250X0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTcGVlZEF2Z19NcGgKICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKcm0oQWxsRGF5c19EaXJDaGFuZ2UpCnN0cihBbGxEYXlzX05ld09yZGVyKQoKIyBWaWV3KGhlYWQoQWxsRGF5c19OZXdPcmRlciwgNTAwKSkKVmlldyh0YWlsKEFsbERheXNfTmV3T3JkZXIsIDUwMCkpCgpgYGAKCgpTdW1tYXJpemluZyB0aGUgZGF0YSB0byBoZWxwIHNwb3QgYW5vbW9saWVzLgpgYGB7cn0KCnN1bW1hcnkoQWxsRGF5c19OZXdPcmRlcikKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpWaWV3KFRyYXZEaXN0TWlfUGN0aWxlcyk6IDk5JSBvZiBUcmF2ZWxEaXN0YW5jZV9NaSBhcmUgYWJvdXQgMSBtaWxlIG9yIGxlc3MuLi5idXQgc29tZSB3ZWlyZCBUcmF2ZWxEaXN0YW5jZV9NaSB2YWx1ZXMgKGUuZy4sIDU4NCBtaWxlcyB0cmF2ZWxlZCkgZXhpc3QuCmBgYHtyfQoKVHJhdkRpc3RNaV9OdGlsZSA8LSBhcy5kYXRhLmZyYW1lKEFsbERheXNfTmV3T3JkZXIkVHJhdmVsRGlzdGFuY2VfTWkpICU+JSAKICBtdXRhdGUoI1BjdGlsZSA9IG50aWxlKEFsbERheXNfTmV3T3JkZXIkVHJhdmVsRGlzdGFuY2VfTWksIDEwMCksCiAgICAgICAgICNNaW5SID0gbWluX3JhbmsoQWxsRGF5c19OZXdPcmRlciRUcmF2ZWxEaXN0YW5jZV9NaSksCiAgICAgICAgIFBjdFIgPSBwZXJjZW50X3JhbmsoQWxsRGF5c19OZXdPcmRlciRUcmF2ZWxEaXN0YW5jZV9NaSksCiAgICAgICAgIFBjdFJfUm91bmQgPSByb3VuZChQY3RSLCAyKQogICAgICAgICkgCgpjb2xuYW1lcyhUcmF2RGlzdE1pX050aWxlKVsxXSA8LSAiVHJhdmVsRGlzdGFuY2VfTWkiCiMgc3RyKFRyYXZEaXN0TWlfTnRpbGUpCgpUcmF2RGlzdE1pX050aWxlX1Jvd3MgPC0gbnJvdyhUcmF2RGlzdE1pX050aWxlKQoKIyBWaWV3KHRhaWwoVHJhdkRpc3RNaV9OdGlsZSwgNTAwKSkKCgpUcmF2RGlzdE1pX1BjdGlsZXMgPC0gZ3JvdXBfYnkoVHJhdkRpc3RNaV9OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgTWluVHJhdkRpc3RNaUF0UGN0aWxlID0gbWluKFRyYXZlbERpc3RhbmNlX01pKSwKICAgIENudHNBdFBjdGlsZSA9IG4oKSwKICAgIFBjdHNBdFBjdGlsZSA9IENudHNBdFBjdGlsZSAvIFRyYXZEaXN0TWlfTnRpbGVfUm93cwogICkgJT4lIAogIG11dGF0ZShDdW1TdW1QQXRQID0gY3Vtc3VtKFBjdHNBdFBjdGlsZSkKICAgICAgICApCgpWaWV3KFRyYXZEaXN0TWlfUGN0aWxlcykKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpXaHkgYXJlIHNvbWUgVHJhdmVsRGlzdGFuY2VfTWkgIk5BIj8gSXQgbG9va3MgbGlrZSBwYXJ0aWFsbHkgYmVjYXVzZSB0aGUgcmVjb3JkcyBhcmUgdGhlIGZpcnN0IHRyaXAgb2YgdGhlIGRheSAoZm9yIHRoYXQgYnVzKSwgc28gSSBwdXJwb3NlZnVsbHkgc2V0IHRoZSBkaXN0YW5jZSB0byAiTkEiLiBBbm90aGVyIHJlYXNvbiBpcyBkdWUgdG8gdGhlIG9kb21ldGVyIHJlY29yZGluZyBhIHZhbHVlIGxlc3MgdGhhbiB0aGUgcHJldmlvdXMgb2RvbWV0ZXIgcmVjb3JkaW5nLiBJbiBtb3N0IGNhc2VzLCBJIGhhdmUgbm8gZXhwbGFuYXRpb24gZm9yIHRoaXMgLSB0aG91Z2ggSSBoYXZlIG9ic2VydmVkIGFib3V0IDY3JSBvZiBhbGwgaW5zdGFuY2VzIHdoZXJlIFRyYXZlbERpc3RhbmNlX01pIGlzIE5BIChvdGhlciB0aGFuIGJlY2F1c2UgaXQncyB0aGUgZmlyc3QgcmVjb3JkIG9mIHRoZSBkYXkpIGFyZSBpbnN0YW5jZXMgd2hlcmUgRGlyQ2hhbmdlMiBpcyAiQ2hhbmdlIi4gVGhpcyBpcyB3ZWlyZCBhbmQgc2hvdWxkIGJlIGFza2VkIHRvIFdNQVRBLgpgYGB7cn0KCnJtKFRyYXZEaXN0TWlfTnRpbGUpCnJtKFRyYXZEaXN0TWlfTnRpbGVfUm93cykKCiMgVmlldyhoZWFkKEFsbERheXNfTmV3T3JkZXIsIDUwMCkpCgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBCdXNEYXlfRXZlbnROdW0gIT0gMSAjIFdoZW4gQnVzRGF5X0V2ZW50TnVtID09IDEsIFRyYXZlbERpc3RhbmNlX01pIGlzIE5BIGJ5IGRlc2lnbiAoZG9uJ3Qgd2FudCB0byBjYWxjdWxhdGUgZGlzdGFuY2UgYmFzZWQgb24geWVzdGVyZGF5J3MgcG9zaXRpb24pCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBncm91cF9ieShTdGFydFN0b3BfSUQpICU+JSAKICAgICAgIHN1bW1hcmlzZShDbnRzID0gc3VtKGlzLm5hKFRyYXZlbERpc3RhbmNlX01pKQogICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoZGVzYyhDbnRzKQogICAgICAgICAgICAgICkKICAgICkKClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgIFN0YXJ0U3RvcF9JRCA9PSAiMTAwMDI0NS0tMTAwMDIxMSIKICAgICAgICAgICApICU+JSAKICAgICAgIHNlbGVjdChSb3dOdW1fT0csCiAgICAgICAgICAgICAgU3RhcnRTdG9wX0lELAogICAgICAgICAgICAgIEV2ZW50X1RpbWUsCiAgICAgICAgICAgICAgRXZlbnRfVGltZV9Ickdyb3VwLAogICAgICAgICAgICAgIEJ1c19JRCwKICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSwKICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzLAogICAgICAgICAgICAgIFREX01pX1NTX01lYW4sCiAgICAgICAgICAgICAgVERfTWlfU1NfTWVhbl9GLAogICAgICAgICAgICAgIFREX01pX1NTSEdfTWVhbiwKICAgICAgICAgICAgICBURF9NaV9TU0hHX01lYW5fRiwKICAgICAgICAgICAgICBURF9NaV9TU19NZWQsCiAgICAgICAgICAgICAgVERfTWlfU1NfTWVkX0YsCiAgICAgICAgICAgICAgVERfTWlfU1NIR19NZWQsCiAgICAgICAgICAgICAgVERfTWlfU1NIR19NZWRfRiwKICAgICAgICAgICAgICBURF9NaV9TU19DbnQsCiAgICAgICAgICAgICAgVERfTWlfU1NfQ250X0YsCiAgICAgICAgICAgICAgVERfTWlfU1NIR19DbnQsCiAgICAgICAgICAgICAgVERfTWlfU1NIR19DbnRfRgogICAgICAgICAgICAgICkgJT4lIAogICAgICAgbXV0YXRlKFJhdGlvX01lYW5Ub0h2cnMgPSBURF9NaV9TU19NZWFuIC8gVHJhdmVsRGlzdGFuY2VfTWlfSHZycykgJT4lIAogICAgICAgYXJyYW5nZShFdmVudF9UaW1lKQogICAgKQoKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpCiAgICAgICAgICAgKQogICAgKQoKIyBUaGVzZSByZWNvcmRzIGFyZSBOQSBiZWN1YXNlIHRoZSByZWNvcmQgaXMgdGhlIGZpcnN0IHJlY29yZCBvZiB0aGUgZGF5ICh0aGUgRXZlbnRfVGltZV9EYXRlKQpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgMzI2LCAzNDYpIHwgIyAzMzYKICAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgNTkxLCA2MTEpIHwgIyA2MDEKICAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgODQ1LCA4NjUpICMgODU1CiAgICAgICAgICAgKQogICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaS4KClRoZXNlIHJlY29yZHMgYXJlIE5BIGJlY3Vhc2UgdGhlIGN1cnJlbnQgcmVjb3JkIG9kb21ldGVyIGlzIGxlc3MgdGhhbiB0aGUgcHJldmlvdXMgcmVjb3JkIG9kb21ldGVyLiBUaGVvcmV0aWNhbGx5LCB0aGlzIHNob3VsZCBOT1QgaGFwcGVuLiBNZTogaXQgYXBwZWFycyB0aGF0IGFib3V0IDY3JSBvZiBhbGwgaW5zdGFuY2VzIHdoZXJlIFRyYXZlbERpc3RhbmNlX01pIGlzIE5BIChvdGhlciB0aGFuIGJlY2F1c2UgaXQncyB0aCBmaXJzdCByZWNvcmQgb2YgdGhlIGRheSkgYXJlIGluc3RhbmNlcyB3aGVyZSBEaXJDaGFuZ2UyIGlzICJDaGFuZ2UiLiBUaGlzIGlzIHdlaXJkIGFuZCBzaG91bGQgYmUgYXNrZWQgdG8gV01BVEEuCmBgYHtyfQoKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDE5NCwgMjE0KSB8ICMgMjA0CiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ0MCwgNDYwKSB8ICMgNDUwCiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ3OCwgNDk4KSB8ICMgNDg4CiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDUxMCwgNTMwKSAjIDUyMAogICAgICAgICAgICkKICAgICkKClRlc3RUYWJsZSA8LSBmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgICAgICAgICBCdXNEYXlfRXZlbnROdW0gIT0gMQogICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFRyYXZlbERpc3RhbmNlX05BID0gYXMuZmFjdG9yKGlmZWxzZShpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJ1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRmFsc2UiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgKSAlPiUKICBncm91cF9ieShEaXJDaGFuZ2UyLCBUcmF2ZWxEaXN0YW5jZV9OQSkgJT4lCiAgc3VtbWFyaXNlKFRyYXZEaXN0TWlfTkFDbnRzID0gbigpCiAgICAgICAgICAgKQoKIyBUZXN0VGFibGUKClRlc3RUYWJsZV9TcHJlYWQgPC0gYXMuZGF0YS5mcmFtZShzcHJlYWQoVGVzdFRhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX05BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZEaXN0TWlfTkFDbnRzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHNlbGVjdChGYWxzZSwKICAgICAgICAgVHJ1ZQogICAgICAgICkKCnJvdy5uYW1lcyhUZXN0VGFibGVfU3ByZWFkKSA8LSBjKCJDaGFuZ2UiLCAiU2FtZSIpCiMgc3RyKFRlc3RUYWJsZV9TcHJlYWQpClRlc3RUYWJsZV9TcHJlYWQKCnByb3AudGFibGUoYXMudGFibGUoYXMubWF0cml4KFRlc3RUYWJsZV9TcHJlYWQpCiAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIDEKICAgICAgICAgICkKCnByb3AudGFibGUoYXMudGFibGUoYXMubWF0cml4KFRlc3RUYWJsZV9TcHJlYWQpCiAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIDIKICAgICAgICAgICkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpMZXQncyBsb29rIGF0IGp1c3QgdGhlIFRyYXZlbERpc3RhbmNlX01pIHZhbHVlcyB0aGF0IGFyZSBOT1QgIk5BIi4KYGBge3J9CgpybShUZXN0VGFibGUpCnJtKFRlc3RUYWJsZV9TcHJlYWQpCgpUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BIDwtIGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFRyYXZlbERpc3RhbmNlX01pICE9IDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKZGltKEFsbERheXNfTmV3T3JkZXIpCmRpbShUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BKQpucm93KEFsbERheXNfTmV3T3JkZXIpIC0gbnJvdyhUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BKQoKc3RyKFRyYXZlbERpc3RhbmNlX01pX05vTkEpCnN1bW1hcnkoVHJhdmVsRGlzdGFuY2VfTWlfTm9OQSkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpMZXQncyBwbG90IGp1c3QgdGhlIFRyYXZlbERpc3RhbmNlX01pIHZhbHVlcyB0aGF0IGFyZSBOT1QgIk5BIi4KYGBge3J9CgpUcmF2RGlzdE1pX0hpc3REZW4gPC0gZ2dwbG90KHNlbGVjdChUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBUcmF2ZWxEaXN0YW5jZV9NaSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IC4uZGVuc2l0eS4uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjA1LCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG91ciA9ICJncmV5NjAiLCBzaXplID0gMC4yKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAiZGVuc2l0eSIsIGNvbG91ciA9ICJyZWQiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDEuNSksIHlsaW0gPSBjKDAsIDQuMCkKICAgICAgICAgICAgICAgICApICsKICBsYWJzKHRpdGxlID0gIlZhcmlhdGlvbiBpbiBEaXN0YW5jZSBCZXR3ZWVuIFN0b3BzIiwKICAgICAgIHggPSAiVHJhdmVsIERpc3RhbmNlIChtaWxlcykiLAogICAgICAgeSA9ICJEZW5zaXR5IgogICAgICApCgpUcmF2RGlzdE1pX0hpc3REZW4KCmBgYAoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaS4KCkxvb2tpbmcgYXQgdGhlIGV4dHJlbWVseSBsYXJnZSBUcmF2ZWxEaXN0YW5jZV9NaSB2YWx1ZXMuIFNvbWUgKGFwcm94IDI3JSkgb2YgVHJhdmVsRGlzdGFuY2VfTWkgdmFsdWVzID4gMSBtaWxlIGFyZSB3aGVuIHRoZSBEaXJDaGFuZ2UyIGNoYW5nZXMuLi5idXQgd2hhdCBhYm91dCB0aGUgb3RoZXIgfjczJT8KYGBge3J9CgpybShUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BKQoKIyBleGFtcGxlcyBvZiB3ZWlyZGx5IGxhcmdlIFRyYXZlbERpc3RhbmNlX01pClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pID4gMS4xNTg3MTIxMjEyICMgMS4xNTg3MTIxMjEyIGlzIHRoZSA5OXRoIHBlcmNlbnRpbGUKICAgICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoZGVzYyhUcmF2ZWxEaXN0YW5jZV9NaSkKICAgICAgICAgICAgICApCiAgICApCgoKIyBXaHkgYXJlIHRoZXNlIGV4dHJlbWVzPyAgQWlycG9ydHM/ICBCdXMgY29sbGVjdGlvbiBwb2ludHM/ClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDA0NCwgNDk0MDY0KSB8ICMgNDk0MDU0CiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDI3MywgNDk0MjkzKSB8ICMgNDk0MjgzCiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDYyNiwgNDk0NjQ2KSB8ICMgNDk0NjM2CiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDE2MTAxNTYsIDE2MTAxNzYpIHwgIyAxNjEwMTY2CiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDIwNzMwNzQsIDIwNzMwOTQpICMgMjA3MzA4NAogICAgICAgICAgICkKICAgICkKCiMgQmVmb3JlIFJlbW92aW5nIFJ1bnMKIyBWaWV3KGZpbHRlcihBbGxEYXlzX1NvcnRlZCwKIyAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgNDk0MDQ0LCA0OTQwNjQpIHwgIyA0OTQwNTQKIyAgICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCA0OTQyNzMsIDQ5NDI5MykgfCAjIDQ5NDI4MwojICAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDYyNiwgNDk0NjQ2KSB8ICMgNDk0NjM2CiMgICAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgMTYxMDE1NiwgMTYxMDE3NikgfCAjIDE2MTAxNjYKIyAgICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCAyMDczMDc0LCAyMDczMDk0KSAjIDIwNzMwODQKIyAgICAgICAgICAgICkKIyAgICAgKQoKIyBBZnRlciBSZW1vdmluZyBSdW5zCiMgVmlldyhmaWx0ZXIoQWxsRGF5c19GaXJzdFN0b3BJRCwKIyAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgNDk0MDQ0LCA0OTQwNjQpIHwgIyA0OTQwNTQKIyAgICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCA0OTQyNzMsIDQ5NDI5MykgfCAjIDQ5NDI4MwojICAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDYyNiwgNDk0NjQ2KSB8ICMgNDk0NjM2CiMgICAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgMTYxMDE1NiwgMTYxMDE3NikgfCAjIDE2MTAxNjYKIyAgICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCAyMDczMDc0LCAyMDczMDk0KSAjIDIwNzMwODQKIyAgICAgICAgICAgICkKIyAgICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaS4KCkFueSByZWxhdGlvbiB3aXRoIERpckNoYW5nZTI/ICBEb2Vzbid0IGxvb2sgYXMgaWYgdGhpcyBpcyBzby4KYGBge3J9CgpFeHRyZW1lVHJhdkRpc3QgPC0gZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pKQogICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFRyYXZEaXN0X0V4dHJlbWUgPSBpZmVsc2UoVHJhdmVsRGlzdGFuY2VfTWkgPiAxLjE1ODcxMjEyMTIsICMgMS4xNTg3MTIxMjEyIGlzIHRoZSA5OXRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJ1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZhbHNlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIGdyb3VwX2J5KERpckNoYW5nZTIsIFRyYXZEaXN0X0V4dHJlbWUpICU+JSAKICBzdW1tYXJpc2UoVHJhdkRpc3RNSV9FeHRDbnRzID0gbigpCiAgICAgICAgICAgKQoKIyBFeHRyZW1lVHJhdkRpc3QKCgpFeHRyZW1lVHJhdkRpc3RfU3ByZWFkIDwtIGFzLmRhdGEuZnJhbWUoc3ByZWFkKEV4dHJlbWVUcmF2RGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2RGlzdF9FeHRyZW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZEaXN0TUlfRXh0Q250cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzZWxlY3QoRmFsc2UsCiAgICAgICAgIFRydWUKICAgICAgICApCgpyb3cubmFtZXMoRXh0cmVtZVRyYXZEaXN0X1NwcmVhZCkgPC0gYygiQ2hhbmdlIiwgIlNhbWUiKQojIHN0cihFeHRyZW1lVHJhdkRpc3RfU3ByZWFkKQojIEV4dHJlbWVUcmF2RGlzdF9TcHJlYWQKCnByb3AudGFibGUoYXMudGFibGUoYXMubWF0cml4KEV4dHJlbWVUcmF2RGlzdF9TcHJlYWQpCiAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIDEKICAgICAgICAgICkKCnByb3AudGFibGUoYXMudGFibGUoYXMubWF0cml4KEV4dHJlbWVUcmF2RGlzdF9TcHJlYWQpCiAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIDIKICAgICAgICAgICkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpMb29raW5nIGF0IHNwZWNpZmljIGJ1c2VzIGFuZCBTdGFydFN0b3BfSUQuCmBgYHtyfQoKcm0oRXh0cmVtZVRyYXZEaXN0KQpybShFeHRyZW1lVHJhdkRpc3RfU3ByZWFkKQoKVmlldyhhcnJhbmdlKGdyb3VwX2J5KEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICAgICAgICAgICBCdXNfSUQKICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgICAgICAgICAgICAgIHN1bW1hcmlzZShEaXN0VHJhdl9NZWFuID0gbWVhbihUcmF2ZWxEaXN0YW5jZV9NaSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgIERpc3RUcmF2X01lZCA9IG1lZGlhbihUcmF2ZWxEaXN0YW5jZV9NaSwgbmEucm0gPSBUUlVFKQogICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgZGVzYyhEaXN0VHJhdl9NZWQpCiAgICAgICAgICAgICkKICAgICkKCgojIGV4YW1wbGUgb2YgZXh0cmVtZWx5IHNtYWxsIFRyYXZlbERpc3RhbmNlX01pIHZhbHVlcyAobG9va3MgbGlrZSB0aGUgb2RvbWV0ZXIgd2Fzbid0IGZ1bmN0aW9uaW5nKQpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBCdXNfSUQgPT0gNjExMSB8CiAgICAgICAgICAgICAgQnVzX0lEID09IDcyMDEgfAogICAgICAgICAgICAgIEJ1c19JRCA9PSA4MDU4CiAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKEJ1c19JRCwgRXZlbnRfVGltZSkKICAgICkKCgpWaWV3KGFycmFuZ2UoZ3JvdXBfYnkoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgICAgICAgICAgIFN0YXJ0U3RvcF9JRAogICAgICAgICAgICAgICAgICAgICApICU+JSAKICAgICAgICAgICAgICAgc3VtbWFyaXNlKERpc3RUcmF2X01lYW4gPSBtZWFuKFRyYXZlbERpc3RhbmNlX01pLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgRGlzdFRyYXZfTWVkID0gbWVkaWFuKFRyYXZlbERpc3RhbmNlX01pLCBuYS5ybSA9IFRSVUUpCiAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICBkZXNjKERpc3RUcmF2X01lZCkKICAgICAgICAgICAgKQogICAgKQoKIyBleGFtcGxlIG9mIGV4dHJlbWVseSBsYXJnZSBUcmF2ZWxEaXN0YW5jZV9NaSB2YWx1ZXMuLi5ubyBpZGVhIHdoeS4uLgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBTdGFydFN0b3BfSUQgPT0gIjEwMDM2NjUtLTEyIiB8CiAgICAgICAgICAgICAgU3RhcnRTdG9wX0lEID09ICIxMDAzNjY1LS01MDAxOTI1IiB8CiAgICAgICAgICAgICAgU3RhcnRTdG9wX0lEID09ICIzMDAxMDM4LS0zMDAyNTY1IgogICAgICAgICAgICkgJT4lIAogICAgICAgYXJyYW5nZShTdGFydFN0b3BfSUQsIEV2ZW50X1RpbWUpCiAgICApCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbERpc3RhbmNlX01pICYgVHJhdmVsRGlzdGFuY2VfTWlfTmV3LgoKSWYgVHJhdmVsRGlzbnRhY2VfTWkgaXMgYmVsb3cgdGhlIDV0aCBwZXJjZW50aWxlIGZvciB0aGF0IFN0YXJ0U3RvcF9JRCwgb3IgaWYgVHJhdmVsRGlzbnRhY2VfTWkgaXMgYWJvdmUgdGhlIDk1dGggcGVyY2VudGlsZSBmb3IgdGhhdCBTdGFydFN0b3BfSUQsIG9yIGlmIFRyYXZlbERpc3RhbmNlX01pIGlzIE5BICh3aGVuIHRoZSBCdXNEYXlfRXZlbnROdW0gIT0xKSwgY29uc2lkZXIgdGhpcyBhbiBvdXRsaWVyLiAgSW4gdGhpcyBjYXNlLCByZXBsYWNlIHRoZSB2YWx1ZSB3aXRoIHRoZSBtZWFuIGZvciB0aGF0IFN0YXJ0U3RvcF9JRCBhbmQgSG91ckdyb3VwIChURF9NaV9TU0hHX01lYW5fRiksIG9yIGlmIHRoZXJlIGFyZSBub3QgZW5vdWdoIHZhbHVlcyBhdCB0aGUgSG91ckdyb3VwIGxldmVsLCByZXBsYWNlIGl0IHdpdGggdGhlIG1lYW4gZm9yIHRoYXQgU3RhcnRTdG9wX0lELgpgYGB7cn0KCiMgVmlldyh0YWlsKEFsbERheXNfTmV3T3JkZXIsIDUwMCkpCgpBbGxEYXlzX05ld1RyYXZlbERpc3QgPC0gCiAgbXV0YXRlKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ldyA9IGlmZWxzZSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChUcmF2ZWxEaXN0YW5jZV9NaSA8IFREX01pX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSA+IFREX01pX1NTSEdfcTk1CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU0hHX0NudF9GID49IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NIR19NZWFuX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChUcmF2ZWxEaXN0YW5jZV9NaSA8IFREX01pX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSA+IFREX01pX1NTSEdfcTk1CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU0hHX0NudF9GIDwgMjAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19DbnRfRiA+PSAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTX01lYW5fRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaSkgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFRyYXZlbERpc3RhbmNlX01pIDwgVERfTWlfU1NIR19xNSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pID4gVERfTWlfU1NIR19xOTUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTX0NudF9GIDwgMjAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19DbnQgPj0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19NZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzICE9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzID09IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19NZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkpKSksCiAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ld19MYWJlbCA9IAogICAgICAgICAgIGZhY3RvcihpZmVsc2UoIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIChUcmF2ZWxEaXN0YW5jZV9NaSA8IFREX01pX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSA+IFREX01pX1NTSEdfcTk1CiAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU0hHX0NudF9GID49IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgIlREX01pX1NTSEdfTWVhbl9GIiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaSkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAoVHJhdmVsRGlzdGFuY2VfTWkgPCBURF9NaV9TU0hHX3E1IHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWkgPiBURF9NaV9TU0hHX3E5NQogICAgICAgICAgICAgICAgICAgICAgICAgICApICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NIR19DbnRfRiA8IDIwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfQ250X0YgPj0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAiVERfTWlfU1NfTWVhbl9GIiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaSkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAoVHJhdmVsRGlzdGFuY2VfTWkgPCBURF9NaV9TU0hHX3E1IHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWkgPiBURF9NaV9TU0hHX3E5NQogICAgICAgICAgICAgICAgICAgICAgICAgICApICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfQ250X0YgPCAyMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTX0NudCA+PSAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICJURF9NaV9TU19NZWFuIiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKGlzLm5hKFRyYXZlbERpc3RhbmNlX01pKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEJ1c0RheV9FdmVudE51bSAhPSAxICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycyAhPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIlRyYXZlbERpc3RhbmNlX01pX0h2cnMiLAogICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzID09IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19NZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgIlRyYXZlbERpc3RhbmNlX01pIgogICAgICAgICAgICAgICAgICAgICAgICApKSkpKQogICAgICAgICAgICAgICAgICkKICAgICAgICApCgpzdHIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0KQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pX0h2cnMgJiBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcuCgpRdWljayBzdW1tYXJ5IGFuZCB0aGVuIGNvcnJlbGF0aW9uIGNhbGN1bGF0aW9uLgpgYGB7cn0KCnJtKEFsbERheXNfTmV3T3JkZXIpCgoKIyAzOCByb3dzIG1lZXQgdGhpcyBjcml0ZXJpYSBhbnltb3JlICAtLSAgYXBwZWFycyB0byBiZSB0aGUgY2FzZSB3aGVuIGJvdGggdGhlIExhdCBMb25nIGNhbGN1bGF0aW9ucywgYW5kIHRoZSBUcmF2ZWxEaXN0YW5jZSBjYWxjdWxhdGlvbnMgZGlkIG5vdCBmdW5jdGlvbiBwcm9wZXJseS4KVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICBpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaV9OZXcpICYKICAgICAgICAgICAgICBCdXNEYXlfRXZlbnROdW0gIT0gMQogICAgICAgICAgICkKICAgICkKCgpzdW1tYXJ5KHNlbGVjdChBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzLAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcKICAgICAgICAgICAgICApCiAgICAgICApCgpzdW1tYXJ5KHNlbGVjdChmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEKICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWksCiAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX0h2cnMsCiAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ldwogICAgICAgICAgICAgICkKICAgICAgICkKCgpjb3Ioc2VsZWN0KEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSwKICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzLAogICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ldwogICAgICAgICAgKSwKICAgIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiCiAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pX0h2cnMgJiBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcuCgpHcmFwaGluZyB0aGUgdHdvIG1ldGhvZHMgb2YgY2FsY3VsYXRpbmcgVHJhdmVsRGlzdGFuY2VfTWkuCgpGaXJzdCwgbGV0J3MgZ2V0IGNyZWF0ZSBhIGZ1bmN0aW9uIHRvIHBsb3QgdGhlIGxpbmVyIG1vZGVsIGVxdWF0aW9uLgpgYGB7cn0KCmxtX2VxbiA8LSBmdW5jdGlvbihkZiwgeSwgeCl7CiAgbSA8LSBsbSh5IH4geCwgZGYpCiAgCiAgbCA8LSBsaXN0KGEgPSBmb3JtYXQoY29lZihtKVsxXSwgZGlnaXRzID0gMiksCiAgICAgICAgICAgIGIgPSBmb3JtYXQoYWJzKGNvZWYobSlbMl0pLCBkaWdpdHMgPSAyKSwKICAgICAgICAgICAgczEgPSBpZmVsc2UodGVzdCA9IGNvZWYobSlbMl0gPiAwLAogICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAiKyIsCiAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gIi0iCiAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgcjIgPSBmb3JtYXQoc3VtbWFyeShtKSRyLnNxdWFyZWQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDMKICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgKQogIAogIGVxIDwtIHN1YnN0aXR1dGUoaXRhbGljKHkpID09IGF+fnMxfn5iICUuJSBpdGFsaWMoeCkqIiwifn5pdGFsaWMocileMn4iPSJ+cjIsCiAgICAgICAgICAgICAgICAgICBsCiAgICAgICAgICAgICAgICAgICkKICAKICBhcy5jaGFyYWN0ZXIoYXMuZXhwcmVzc2lvbihlcSkKICAgICAgICAgICAgICApICAgICAgICAgICAgIAp9CgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbERpc3RhbmNlX01pICYgVHJhdmVsRGlzdGFuY2VfTWlfSHZycyAmIFRyYXZlbERpc3RhbmNlX01pX05ldy4KClNjYXR0ZXIgcGxvdCAodXNpbmcgYSAxMCUgc2FtcGxlIHRvIG1ha2luZyBwbG90dGluZyB0aW1lIGZhc3RlciBhbmQgdG8gcmVkdWNlIHVuLW5lZWRlZCBkYXRhIGluIHRoZSAic2FtZSIgc3Bsb3QpLgpgYGB7cn0KCnNldC5zZWVkKDEyMzQ1Njc4OSkKQWxsRGF5c19OZXdUcmF2ZWxEaXN0XzEwUGN0IDwtIGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgcmVuYW1lKERpc3RNZXRob2QgPSBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdfTGFiZWwpICU+JSAKICBzYW1wbGVfZnJhYygwLjEpCgoKVHJhdkRpc3RfTWlWc0NhbGMgPC0gZ2dwbG90KHNlbGVjdChBbGxEYXlzX05ld1RyYXZlbERpc3RfMTBQY3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpc3RNZXRob2QKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IFRyYXZlbERpc3RhbmNlX01pX05ldywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gVHJhdmVsRGlzdGFuY2VfTWksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gRGlzdE1ldGhvZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoInJlZCIsImJsdWUiLCAiZ3JlZW4iLCAib3JhbmdlIikKICAgICAgICAgICAgICAgICAgICAgKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDEsIGFscGhhID0gMC41KSArCiAgc2NhbGVfc2hhcGUoc29saWQgPSBGQUxTRSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG91ciA9ICJibHVlIikgKwogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgY29sb3VyID0gInJlZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMS41KSwgeWxpbSA9IGMoMCwgMS41KQogICAgICAgICAgICAgICAgICkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMS41LCAwLjI1KQogICAgICAgICAgICAgICAgICAgICkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMS41LCAwLjI1KQogICAgICAgICAgICAgICAgICAgICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44NSwgMC40MCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpCiAgICAgICApICsKICBhbm5vdGF0ZShsYWJlbCA9IGxtX2VxbihkZiA9IEFsbERheXNfTmV3VHJhdmVsRGlzdF8xMFBjdCwKICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQWxsRGF5c19OZXdUcmF2ZWxEaXN0XzEwUGN0JFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBBbGxEYXlzX05ld1RyYXZlbERpc3RfMTBQY3QkVHJhdmVsRGlzdGFuY2VfTWlfTmV3CiAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICMgeCA9IDYyLAogICAgICAgICAgICMgeSA9IDIwLAogICAgICAgICAgIHggPSAxLjE1LAogICAgICAgICAgIHkgPSAxLjQ1LAogICAgICAgICAgIGdlb20gPSAidGV4dCIsCiAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgY29sb3VyID0gImJsdWUiLAogICAgICAgICAgIHBhcnNlID0gVFJVRQogICAgICAgICAgKSArCiAgYW5ub3RhdGUobGFiZWwgPSAiUmVmZXJlbmNlIExpbmUgKHNsb3BlID0gMSkiLAogICAgICAgICAgICMgeCA9IDE2LAogICAgICAgICAgICMgeSA9IDMwLAogICAgICAgICAgIHggPSAxLjMyLAogICAgICAgICAgIHkgPSAxLjA1LAogICAgICAgICAgIGdlb20gPSAidGV4dCIsCiAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgY29sb3VyID0gInJlZCIKICAgICAgICAgICkgKwogIGxhYnModGl0bGUgPSAiVHJhdmVsRGlzdGFuY2VfTWkgdnMuIFRyYXZlbERpc3RhbmNlX01pX05ldyIsCiAgICAgICB4ID0gIlRyYXZlbERpc3RhbmNlX01pX05ldyIsCiAgICAgICB5ID0gIlRyYXZlbERpc3RhbmNlX01pIgogICAgICApCiMgKwojICAgZ2VvbV9qaXR0ZXIoKQoKVHJhdkRpc3RfTWlWc0NhbGMKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkgJiBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzICYgVHJhdmVsRGlzdGFuY2VfTWlfTmV3LgoKR3JhcGhpbmcgdGVzdCB3aXRoIHJib2tlaC4KYGBge3J9CgpUcmF2RGlzdF9NaVZzQ2FsY19Cb2tlaCA8LSBmaWd1cmUoZGF0YSA9IHNlbGVjdChBbGxEYXlzX05ld1RyYXZlbERpc3RfMTBQY3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ldywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpc3RNZXRob2QKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxpbSA9IGMoMCwgMS41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsIDEuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfbG9jYXRpb24gPSAiYm90dG9tX3JpZ2h0IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBseV9wb2ludHMoeCA9IFRyYXZlbERpc3RhbmNlX01pX05ldywKICAgICAgICAgICAgeSA9IFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICBjb2xvciA9IERpc3RNZXRob2QsCiAgICAgICAgICAgIGhvdmVyID0gYyhUcmF2ZWxEaXN0YW5jZV9NaV9OZXcsIFRyYXZlbERpc3RhbmNlX01pLCBEaXN0TWV0aG9kKQogICAgICAgICAgICkgJT4lIAogIGx5X2FibGluZShhID0gMCwgYiA9IDEsIGNvbG9yID0gInJlZCIpCgpUcmF2RGlzdF9NaVZzQ2FsY19Cb2tlaAoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcuCgp+MTElIG9mIHJpZGVzIGFyZSBzdGlsbCBzaG93aW5nIGFzIGxlc3MgdGhhbiAwLjEgbWlsZXMgb2YgVHJhdmVsRGlzdGFuY2VfTWlfTmV3LgpgYGB7cn0KCnJtKFRyYXZEaXN0X01pVnNDYWxjX0Jva2VoKQpybShBbGxEYXlzX05ld1RyYXZlbERpc3RfMTBQY3QpCgoKc3VtbWFyeShBbGxEYXlzX05ld1RyYXZlbERpc3QkVHJhdmVsRGlzdGFuY2VfTWlfTmV3KQoKVHJhdkRpc3RNaU5ld19OdGlsZSA8LSBhcy5kYXRhLmZyYW1lKEFsbERheXNfTmV3VHJhdmVsRGlzdCRUcmF2ZWxEaXN0YW5jZV9NaV9OZXcpICU+JSAKICBtdXRhdGUoIyBQY3RpbGUgPSBudGlsZShBbGxEYXlzX05ld1RyYXZlbERpc3QkVHJhdmVsRGlzdGFuY2VfTWlfTmV3LCAxMDApLAogICAgICAgICAjIE1pblIgPSBtaW5fcmFuayhBbGxEYXlzX05ld1RyYXZlbERpc3QkVHJhdmVsRGlzdGFuY2VfTWlfTmV3KSwKICAgICAgICAgUGN0UiA9IHBlcmNlbnRfcmFuayhBbGxEYXlzX05ld1RyYXZlbERpc3QkVHJhdmVsRGlzdGFuY2VfTWlfTmV3KSwKICAgICAgICAgUGN0Ul9Sb3VuZCA9IHJvdW5kKFBjdFIsIDIpCiAgICAgICAgKSAKCmNvbG5hbWVzKFRyYXZEaXN0TWlOZXdfTnRpbGUpWzFdIDwtICJUcmF2ZWxEaXN0YW5jZV9NaV9OZXciCiMgc3RyKFRyYXZEaXN0TWlOZXdfTnRpbGUpCgpUcmF2RGlzdE1pTmV3X050aWxlX1Jvd3MgPC0gbnJvdyhUcmF2RGlzdE1pTmV3X050aWxlKQoKIyBWaWV3KHRhaWwoVHJhdkRpc3RNaU5ld19OdGlsZSwgNTAwKSkKCgpUcmF2RGlzdE1pTmV3X1BjdGlsZXMgPC0gZ3JvdXBfYnkoVHJhdkRpc3RNaU5ld19OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgTWluVHJhdkRpc3RNaUF0UGN0aWxlID0gbWluKFRyYXZlbERpc3RhbmNlX01pX05ldyksCiAgICBDbnRzQXRQY3RpbGUgPSBuKCksCiAgICBQY3RzQXRQY3RpbGUgPSBDbnRzQXRQY3RpbGUgLyBUcmF2RGlzdE1pTmV3X050aWxlX1Jvd3MKICApICU+JSAKICBtdXRhdGUoQ3VtU3VtUEF0UCA9IGN1bXN1bShQY3RzQXRQY3RpbGUpCiAgICAgICAgKQoKVmlldyhUcmF2RGlzdE1pTmV3X1BjdGlsZXMpCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbERpc3RhbmNlX01pX05ldy4KCldoeSBhcmUgdGhlcmUgc3RpbGwgc29tZSBzbWFsbCBvciB6ZXJvIFRyYXZlbERpc3RhbmNlX01pX05ldyB2YWx1ZXMuCmBgYHtyfQoKcm0oVHJhdkRpc3RNaU5ld19OdGlsZSkKcm0oVHJhdkRpc3RNaU5ld19OdGlsZV9Sb3dzKQoKClZpZXcoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3ID09IDAKICAgICAgICAgICApCiAgICApCgojIGV4YW1wbGVzIG9mIFRyYXZlbERpc3RhbmNlX01pX05ldyB2YWx1ZXMgdGhhdCBhcmUgemVyby4KVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAoUm93TnVtX09HID49IDE2NTIgJiBSb3dOdW1fT0cgPD0gMTY3MikgfCAjIDE2NjIgIC0tICAxc3QgdHJpcCBvZiBhIG5ldyByb3V0ZSAmIG5vIGNoYW5nZSBpbiBsYXQgbG9uCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDkyMzc4ICYgUm93TnVtX09HIDw9IDkyMzk4KSB8ICMgOTIzODggIC0tICBvZG9tZXRlciBhbHdheXMgYXQgemVybyAmIG5vIGNoYW5nZSBpbiBsYXQgbG9uCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDE0NDc0NjIgJiBSb3dOdW1fT0cgPD0gMTQ0NzQ4MikgfCAjIDE0NDc0NzIgIC0tICBubyBjaGFuZ2UgaW4gb2RvbWV0ZXIgJiBubyBjaGFuZ2UgaW4gbGF0IGxvbgogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAxNDg1ODQ1ICYgUm93TnVtX09HIDw9IDE0ODU4NjUpICMgMTQ4NTg1NSAgLS0gIG5vIGNoYW5nZSBpbiBvZG9tZXRlciAmIG5vIGNoYW5nZSBpbiBsYXQgbG9uCiAgICAgICAgICAgKQogICAgKQoKClZpZXcoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3ID4gMCAmCiAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3IDwgMC4wOTg0ODQ4NDg1ICYgICMgMC4wOTg0ODQ4NDg1IGlzIGFuIE1EQVQgZ3Vlc3MgYXQgYSBkaXN0YW5jZSBiZXR3ZWVuIHN0b3BzCiAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfRnQgPT0gMCAgIyBtZWFuaW5nIFRyYXZlbERpc3RhbmNlX01pX05ldyBpcyBiYXNlZCBvbiBIYXZlcnNpbmUgZGlzdGFuY2UgKGxhdCBsb25nIHZhbHVlcykKICAgICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoVHJhdmVsRGlzdGFuY2VfTWlfTmV3KQogICAgKQoKIyBleGFtcGxlcyBvZiBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcgdmFsdWVzIHRoYXQgYXJlIHZlcnkgc21hbGwuIEFsbCBhcmUgZXhhbXBsZXMgb2Ygbm8gY2hhbmdlIGluIHRoZSBvZG9tZXRlciwgYW5kIGV4dHJlbWVseSBzbWFsbCBjaGFuZ2VzIGluIGxhdCBsb24uClZpZXcoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgKFJvd051bV9PRyA+PSA5MjEwMzYgJiBSb3dOdW1fT0cgPD0gOTIxMDU2KSB8ICMgOTIxMDQ2ICAtLSAgCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDIyODEyMzUgJiBSb3dOdW1fT0cgPD0gMjI4MTI1NSkgfCAjIDIyODEyNDUgIC0tICAKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjk1NjUyOCAmIFJvd051bV9PRyA8PSAyOTU2NTQ4KSB8ICMgMjk1NjUzOCAgLS0gIAogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAyOTA5MDA3ICYgUm93TnVtX09HIDw9IDI5MDkwMjcpICMgMjkwOTAxNyAgLS0gIAogICAgICAgICAgICkKICAgICkKCgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ldyA+IDAgJgogICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ldyA8IDAuMDk4NDg0ODQ4NSAmICAjIDAuMDk4NDg0ODQ4NSBpcyBhbiBNREFUIGd1ZXNzIGF0IGEgZGlzdGFuY2UgYmV0d2VlbiBzdG9wcwogICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX0Z0ICE9IDAgICMgbWVhbmluZyBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcgaXMgYmFzZWQgb24gYWN0dWFsIG9kb21ldGVyIHJlYWRpbmdzCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKFRyYXZlbERpc3RhbmNlX01pX05ldykKICAgICkKCiMgZXhhbXBsZXMgb2YgVHJhdmVsRGlzdGFuY2VfTWlfTmV3IHZhbHVlcyB0aGF0IGFyZSB2ZXJ5IHNtYWxsLiBBbGwgYXJlIGV4YW1wbGVzIG9mIGV4dHJlbWVseSBzbWFsbCBjaGFuZ2VzIGluIHRoZSBvZG9tZXRlci4KVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAoUm93TnVtX09HID49IDE2ODEgJiBSb3dOdW1fT0cgPD0gMTcwMSkgfCAjIDE2OTEgIC0tICAKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjEzMSAmIFJvd051bV9PRyA8PSAyMTUxKSB8ICMgMjE0MSAgLS0gIAogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAxNTQ3ODQgJiBSb3dOdW1fT0cgPD0gMTU0ODA0KSB8ICMgMTU0Nzk0ICAtLSAgCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDIyNjc0MzEgJiBSb3dOdW1fT0cgPD0gMjI2NzQ1MSkgIyAyMjY3NDQxICAtLSAgCiAgICAgICAgICAgKQogICAgKQoKYGBgCgoKRXhwbG9yZSBpbnN0YW5jZXMgd2hlcmUgVHJhdmVsRGlzdGFuY2VfTWkgaXMgTkEuCmBgYHtyfQoKVmlldyhncm91cF9ieShBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICAgIFN0YXJ0U3RvcF9JRAogICAgICAgICAgICAgKSAlPiUgCiAgICAgICBzdW1tYXJpc2UoQ250cyA9IHN1bShpcy5uYShUcmF2ZWxUaW1lX1NlYykKICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKGRlc2MoQ250cykKICAgICAgICAgICAgICApCiAgICApCgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBTdGFydFN0b3BfSUQgPT0gIjUwMDQ2MzUtLTUwMDQ3NTgiCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBzZWxlY3QoVHJhdmVsVGltZV9TZWMsCiAgICAgICAgICAgICAgVFRfU2VjX1NTX01lYW4sCiAgICAgICAgICAgICAgVFRfU2VjX1NTSEdfTWVhbiwKICAgICAgICAgICAgICBUVF9TZWNfU1NfTWVkLAogICAgICAgICAgICAgIFRUX1NlY19TU0hHX01lZCwKICAgICAgICAgICAgICBUVF9TZWNfU1NfQ250LAogICAgICAgICAgICAgIFRUX1NlY19TU0hHX0NudAogICAgICAgICAgICAgICkKICAgICkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsVGltZV9Ici4KClZpZXcoVHJhdkRpc3RNaV9QY3RpbGVzKTogOTglIG9mIFRyYXZlbFRpbWVfSHIgYXJlIGJldHdlZW4gNyBzZWNvbmRzIGFuZCA0NjQgc2Vjb25kcyAofjggbWludXRlcykuCmBgYHtyfQoKVHJhdlRpbWVIcl9OdGlsZSA8LSBhcy5kYXRhLmZyYW1lKEFsbERheXNfTmV3VHJhdmVsRGlzdCRUcmF2ZWxUaW1lX0hyKSAlPiUgCiAgbXV0YXRlKFBjdGlsZSA9IG50aWxlKEFsbERheXNfTmV3VHJhdmVsRGlzdCRUcmF2ZWxUaW1lX0hyLCAxMDApLAogICAgICAgICBNaW5SID0gbWluX3JhbmsoQWxsRGF5c19OZXdUcmF2ZWxEaXN0JFRyYXZlbFRpbWVfSHIpLAogICAgICAgICBQY3RSID0gcGVyY2VudF9yYW5rKEFsbERheXNfTmV3VHJhdmVsRGlzdCRUcmF2ZWxUaW1lX0hyKSwKICAgICAgICAgUGN0Ul9Sb3VuZCA9IHJvdW5kKFBjdFIsIDIpCiAgICAgICAgKSAKCmNvbG5hbWVzKFRyYXZUaW1lSHJfTnRpbGUpWzFdIDwtICJUcmF2ZWxUaW1lX0hyIgpzdHIoVHJhdlRpbWVIcl9OdGlsZSkKClRyYXZUaW1lSHJfTnRpbGVfUm93cyA8LSBucm93KFRyYXZUaW1lSHJfTnRpbGUpCgpWaWV3KHRhaWwoVHJhdlRpbWVIcl9OdGlsZSwgNTAwKSkKCgpUcmF2VGltZUhyX1BjdGlsZXMgPC0gZ3JvdXBfYnkoVHJhdlRpbWVIcl9OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgTWluVHJhdlRpbWVIckF0UGN0aWxlID0gbWluKFRyYXZlbFRpbWVfSHIpLAogICAgQ250c0F0UGN0aWxlID0gbigpLAogICAgUGN0c0F0UGN0aWxlID0gQ250c0F0UGN0aWxlIC8gVHJhdlRpbWVIcl9OdGlsZV9Sb3dzCiAgKSAlPiUgCiAgbXV0YXRlKEN1bVN1bVBBdFAgPSBjdW1zdW0oUGN0c0F0UGN0aWxlKSwKICAgICAgICAgTWluVHJhdlRpbWVTZWNBdFBjdGlsZSA9IE1pblRyYXZUaW1lSHJBdFBjdGlsZSAqIDM2MDAKICAgICAgICApCgpWaWV3KFRyYXZUaW1lSHJfUGN0aWxlcykKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsVGltZV9Ici4KCkhpc3RvZ3JhbSBvZiBUcmF2ZWxUaW1lX1NlYy4KYGBge3J9CgpUcmF2VGltZV9TZWNfSGlzdERlbiA8LSBnZ3Bsb3QoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoVHJhdmVsVGltZV9TZWMpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBUcmF2ZWxUaW1lX1NlYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gLi5kZW5zaXR5Li4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUsIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3VyID0gImdyZXk2MCIsIHNpemUgPSAwLjIpICsKICBnZW9tX2xpbmUoc3RhdCA9ICJkZW5zaXR5IiwgY29sb3VyID0gInJlZCIpICsKICAjIHN0YXRfYmluKGJpbndpZHRoID0gNSwKICAjICAgICAgICAgIGdlb20gPSAidGV4dCIsCiAgIyAgICAgICAgICBzaXplID0gMi41LAogICMgICAgICAgICAgdmp1c3QgPSAxLjUsCiAgIyAgICAgICAgICBhZXMobGFiZWwgPSBmb3JtYXQoLi5jb3VudC4uLCBiaWcubWFyayA9ICIsIikKICAjICAgICAgICAgICAgICksCiAgIyAgICAgICAgICkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLCAxODApLCB5bGltID0gYygwLCAwLjAyKQogICAgICAgICAgICAgICAgICkgKwogICMgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlZhcmlhdGlvbiBpbiBUcmF2ZWwgVGltZSIsCiAgICAgICB4ID0gIlRyYXZlbCBUaW1lIChzZWMpIiwKICAgICAgIHkgPSAiRGVuc2l0eSIKICAgICAgKQoKVHJhdlRpbWVfU2VjX0hpc3REZW4KCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsVGltZV9Ici4KCkxvb2tpbmcgYXQgb2RkIFRyYXZlbFRpbWVfU2VjIHZhbHVlcy4KYGBge3J9CgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgIGlzLm5hKFRyYXZlbFRpbWVfU2VjKSAmIAogICAgICAgICAgICAgICFpcy5uYShPZG9tZXRlcl9EaXN0YW5jZV9MYWcxKQogICAgICAgICAgICkKICAgICkKCgojIGV4YW1wbGVzIG9mIFRyYXZlbFRpbWVfU2VjIHZhbHVlcyB0aGF0IGFyZSBOQS4gVGhlc2UgYXJlIE5BIGJlY2F1c2UgdGhlIEV2ZW50X1RpbWUgJiBEZXBhcnR1cmVfVGltZSByZWFkaW5ncyBhcmUgbm90IGFjY3VyYXRlIChpLmUuLCB0aGUgcHJldmlvdXMgRGVwYXJ0dXJlX1RpbWUgaXMgQkVGT1JFIHRoZSBjdXJyZW50IEV2ZW50X1RpbWUpLgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gOTA4MDkgJiBSb3dOdW1fT0cgPD0gOTA4MjkpIHwgIyA5MDgxOQogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSA5MDg4MSAmIFJvd051bV9PRyA8PSA5MDkwMSkgfCAjIDkwODkxCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDk5NDgxMyAmIFJvd051bV9PRyA8PSA5OTQ4MzMpIHwgIyA5OTQ4MjMKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjM5MTM0MiAmIFJvd051bV9PRyA8PSAyMzkxMzYyKSAjIDIzOTEzNTIKICAgICAgICAgICApCiAgICApCgoKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYyA9PSAwCiAgICAgICAgICAgKQogICAgKQoKIyBleGFtcGxlcyB3aGVyZSBUcmF2ZWxUaW1lX1NlYyBpcyB6ZXJvIChpLmUuLCBwcmV2aW91cyBEZXBhcnR1cmVfVGltZSBlcXVhbHMgdGhlIGN1cnJlbnQgRXZlbnRfVGltZSkuClZpZXcoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgKFJvd051bV9PRyA+PSAxNzU3MjUgJiBSb3dOdW1fT0cgPD0gMTc1NzQ1KSB8ICMgMTc1NzM1CiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDQwMTEyNyAmIFJvd051bV9PRyA8PSA0MDExNDcpIHwgIyA0MDExMzcKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjQ0NjgyMCAmIFJvd051bV9PRyA8PSAyNDQ2ODQwKSB8ICMgMjQ0NjgzMAogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAyNTQ1MDM2ICYgUm93TnVtX09HIDw9IDI1NDUwNTYpICMgMjU0NTA0NgogICAgICAgICAgICkKICAgICkKCgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjID4gMCAmCiAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPCAxMAogICAgICAgICAgICkgJT4lIAogICAgICAgYXJyYW5nZShkZXNjKFNwZWVkQXZnX01waCkKICAgICAgICAgICAgICApCiAgICApCgoKIyBleGFtcGxlcyB3aGVyZSBUcmF2ZWxUaW1lX1NlYyBpcyB1bnVzdWFsbHkgc21hbGwgKHdpdGggVHJhdmVsRGlzdGFuY2VfTWkgdmFsdWVzIHRoYXQgYXJlIGxhcmdlKS4KVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAoUm93TnVtX09HID49IDEwNDIyMjggJiBSb3dOdW1fT0cgPD0gMTA0MjI0OCkgfCAjIDEwNDIyMzgKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gNTM4MTYgJiBSb3dOdW1fT0cgPD0gNTM4MzYpIHwgIyA1MzgyNgogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAzNjA1NzEgJiBSb3dOdW1fT0cgPD0gMzYwNTkxKSB8ICMgMzYwNTgxCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDUwMjI3MSAmIFJvd051bV9PRyA8PSA1MDIyOTEpICMgNTAyMjgxIChjYW4ndCBleHBsaWFuIHRoZSB3ZWlyZCBUcmF2ZWxUaW1lX1NlYyBjYWxjdWxhdGlvbiBoZXJlIC0gaXQncyBub3QgZXZlbiBhbiBpbnRlZ2VyISkKICAgICAgICAgICApCiAgICApCgojIHN0aWxsIHRyeWluZyB0byBleHBsYWluIDUwMjI4MS4uLm9uIHRoZSBkYXkgb2YgdGhpcyB3ZWlyZG5lc3MsIHRoZSBidXMgd2FzIG9ubHkgaW4gY2lyY3VsYXRpb24gZm9yIDQtNSBzdG9wcyAofjIwIG1pbnV0ZXMpIG9uIHRoYXQgZGF5IChPY3QgNikKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICBCdXNfSUQgPT0gMjcxMQogICAgICAgICAgICkKICAgICkKCgojIGV4cGxvcmluZyBsYXJnZSB2YWx1ZXMgZm9yIFRyYXZlbFRpbWVfU2VjClZpZXcoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPT0gMzAwCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKGRlc2MoVHJhdmVsVGltZV9TZWMpLAogICAgICAgICAgICAgICBTcGVlZEF2Z19NcGgyCiAgICAgICAgICAgICAgKQogICAgKQoKIyBleGFtcGxlcyB3aGVyZSBUcmF2ZWxUaW1lX1NlYyBpcyB1bnVzdWFsbHkgbGFyZ2UgKHdpdGggVHJhdmVsRGlzdGFuY2VfTWkgdmFsdWVzIHRoYXQgYXJlIHNtYWxsLCBzbyBTcGVlZEF2Z19NcGggdmFsdWVzIGFyZSB2ZXJ5IHNtYWxsKS4KVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAoUm93TnVtX09HID49IDI2Mjc0NTkgJiBSb3dOdW1fT0cgPD0gMjYyNzQ3OSkgfCAjIDI2Mjc0NjkKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjE5MzM0NCAmIFJvd051bV9PRyA8PSAyMTkzMzY0KSB8ICMgMjE5MzM1NAogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAxNjQ0MTIzICYgUm93TnVtX09HIDw9IDE2NDQxNDMpIHwgIyAxNjQ0MTMzCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDg2OTYwMCAmIFJvd051bV9PRyA8PSA4Njk2MjApICMgODY5NjEwCiAgICAgICAgICAgKQogICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBTcGVlZEF2Z19NcGgyCgpWaWV3KFNwZWVkX1BjdGlsZXMpOiA5MCUgb2YgU3BlZWRBdmdfTXBoMiBhcmUgYmV0d2VlbiB+M21waCBhbmQgfjY2bXBoLgpgYGB7cn0KClNwZWVkX050aWxlIDwtIGFzLmRhdGEuZnJhbWUoQWxsRGF5c19OZXdUcmF2ZWxEaXN0JFNwZWVkQXZnX01waDIpICU+JSAKICBtdXRhdGUoUGN0aWxlID0gbnRpbGUoQWxsRGF5c19OZXdUcmF2ZWxEaXN0JFNwZWVkQXZnX01waDIsIDEwMCksCiAgICAgICAgIE1pblIgPSBtaW5fcmFuayhBbGxEYXlzX05ld1RyYXZlbERpc3QkU3BlZWRBdmdfTXBoMiksCiAgICAgICAgIFBjdFIgPSBwZXJjZW50X3JhbmsoQWxsRGF5c19OZXdUcmF2ZWxEaXN0JFNwZWVkQXZnX01waDIpLAogICAgICAgICBQY3RSX1JvdW5kID0gcm91bmQoUGN0UiwgMikKICAgICAgICApIAoKY29sbmFtZXMoU3BlZWRfTnRpbGUpWzFdIDwtICJTcGVlZEF2Z19NcGgyIgpzdHIoU3BlZWRfTnRpbGUpCgpTcGVlZF9OdGlsZV9Sb3dzIDwtIG5yb3coU3BlZWRfTnRpbGUpCgpWaWV3KHRhaWwoU3BlZWRfTnRpbGUsIDUwMCkpCgoKU3BlZWRfUGN0aWxlcyA8LSBncm91cF9ieShTcGVlZF9OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICBQY3RSX1JvdW5kCiAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzdW1tYXJpc2UoCiAgICBNaW5TcGVlZEF0UGN0aWxlID0gbWluKFNwZWVkQXZnX01waDIpLAogICAgQ250c0F0UGN0aWxlID0gbigpLAogICAgUGN0c0F0UGN0aWxlID0gQ250c0F0UGN0aWxlIC8gU3BlZWRfTnRpbGVfUm93cwogICkgJT4lIAogIG11dGF0ZShDdW1TdW1QQXRQID0gY3Vtc3VtKFBjdHNBdFBjdGlsZSkKICAgICAgICApCgpWaWV3KFNwZWVkX1BjdGlsZXMpCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFNwZWVkQXZnX01waDIuCgpFeHBsb3JpbmcgdGhlIHJlbW92YWwgb2Ygb3V0bGllciBUcmF2ZWxUaW1lX1NlYyBhbmQgVHJhdmVsRGlzdGFuY2VfTWkuCmBgYHtyfQoKc3VtbWFyeShzZWxlY3QoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAgICBTcGVlZEF2Z19NcGgsCiAgICAgICAgICAgICAgIFNwZWVkQXZnX01waDIKICAgICAgICAgICAgICApCiAgICAgICApCgpzdW1tYXJ5KHNlbGVjdChmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWkgPiAwLjAwMDE4OTM5MzkgJiAjIGxvd2VzdCBub24temVybyBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pIDwgMS4wODEyNTAwMDAwICYgIyA5OXRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPiAxMC4wNTAwMDAgJiAjIDJuZCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjIDwgMjkzLjAwMDAwMCAjIDk4dGggcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICBTcGVlZEF2Z19NcGgsCiAgICAgICAgICAgICAgIFNwZWVkQXZnX01waDIKICAgICAgICAgICAgICApCiAgICAgICApCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFNwZWVkQXZnX01waDIuCgpIaXN0b2dyYW0gb2YgU3BlZWRBdmdfTXBoMi4KYGBge3J9CgpTcGVlZF9IaXN0RGVuIDwtIGdncGxvdChmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKFNwZWVkQXZnX01waDIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gU3BlZWRBdmdfTXBoMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAuLmRlbnNpdHkuLgogICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSA1LCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG91ciA9ICJncmV5NjAiLCBzaXplID0gMC4yKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAiZGVuc2l0eSIsIGNvbG91ciA9ICJyZWQiKSArCiAgc3RhdF9iaW4oYmlud2lkdGggPSA1LAogICAgICAgICAgIGdlb20gPSAidGV4dCIsCiAgICAgICAgICAgc2l6ZSA9IDIuNSwKICAgICAgICAgICB2anVzdCA9IDEuNSwKICAgICAgICAgICBhZXMobGFiZWwgPSBmb3JtYXQoLi5jb3VudC4uLCBiaWcubWFyayA9ICIsIikKICAgICAgICAgICAgICApLAogICAgICAgICAgKSArCiAgIyBnZW9tX3RleHQoYWVzKGxhYmVsID0gZm9ybWF0KC4uY291bnQuLiwgYmlnLm1hcmsgPSAiLCIpCiAgIyAgICAgICAgICAgICAgKSwKICAjICAgICAgICAgICBzaXplID0gMywKICAjICAgICAgICAgICBudWRnZV95ID0gKC4uY291bnQuLiAqIDAuMSkKICAjICAgICAgICAgICkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLCA3MCksIHlsaW0gPSBjKDAsIDAuMDQpCiAgICAgICAgICAgICAgICAgKSArCiAgIyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGxhYnModGl0bGUgPSAiVmFyaWF0aW9uIGluIFRyYXZlbCBTcGVlZCIsCiAgICAgICB4ID0gIkF2ZXJhZ2UgU3BlZWQgKG1waCkiLAogICAgICAgeSA9ICJEZW5zaXR5IgogICAgICApCgpTcGVlZF9IaXN0RGVuCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFNwZWVkQXZnX01waDIuCgpIaXN0b2dyYW0gb2YgU3BlZWRBdmdfTXBoMiBhZnRlciByZW1vdmluZyBvdXRsaWVyIFRyYXZlbFRpbWVfU2VjIGFuZCBUcmF2ZWxEaXN0YW5jZV9NaS4KYGBge3J9CgpWaWV3KFRyYXZEaXN0TWlOZXdfUGN0aWxlcykKVmlldyhUcmF2VGltZUhyX1BjdGlsZXMpCgpTcGVlZE5vT3V0bGllcl9IaXN0RGVuIDwtIGdncGxvdChmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKFNwZWVkQXZnX01waDIpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3ID4gMC4wNzc4NDEwMDUgJiAjIDV0aCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVHJhdmVsRGlzdGFuY2VfTWlfTmV3IDwgMS4wODEyNTAwMDAwICYgIyA5OXRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPiAxMi4xMDAwMDAgIyA0dGggcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFRyYXZlbFRpbWVfU2VjIDwgMjkzLjAwMDAwMCAjIDk4dGggcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IFNwZWVkQXZnX01waDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gLi5kZW5zaXR5Li4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSwgZmlsbCA9ICJsaWdodGJsdWUiLCBjb2xvdXIgPSAiZ3JleTYwIiwgc2l6ZSA9IDAuMikgKwogIGdlb21fbGluZShzdGF0ID0gImRlbnNpdHkiLCBjb2xvdXIgPSAicmVkIikgKwogIHN0YXRfYmluKGJpbndpZHRoID0gNSwKICAgICAgICAgICBnZW9tID0gInRleHQiLAogICAgICAgICAgIHNpemUgPSAyLjUsCiAgICAgICAgICAgdmp1c3QgPSAxLjUsCiAgICAgICAgICAgYWVzKGxhYmVsID0gZm9ybWF0KC4uY291bnQuLiwgYmlnLm1hcmsgPSAiLCIpCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICkgKwogICMgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZvcm1hdCguLmNvdW50Li4sIGJpZy5tYXJrID0gIiwiKQogICMgICAgICAgICAgICAgICksCiAgIyAgICAgICAgICAgc2l6ZSA9IDMsCiAgIyAgICAgICAgICAgbnVkZ2VfeSA9ICguLmNvdW50Li4gKiAwLjEpCiAgIyAgICAgICAgICApICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgNzApLCB5bGltID0gYygwLCAwLjA0KQogICAgICAgICAgICAgICAgICkgKwogICMgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlZhcmlhdGlvbiBpbiBUcmF2ZWwgU3BlZWQiLAogICAgICAgc3VidGl0bGUgPSAiKHJlbW92ZWQgbG93IG91dGxpZXJzIG9mIFRyYXZlbCBEaXN0YW5jZSBhbmQgVHJhdmVsIFRpbWUpIiwKICAgICAgIHggPSAiQXZlcmFnZSBTcGVlZCAobXBoKSIsCiAgICAgICB5ID0gIkRlbnNpdHkiCiAgICAgICkKClNwZWVkTm9PdXRsaWVyX0hpc3REZW4KCmBgYAoKCkludmVzdGlnYXRpb24gb2YgU3BlZWRBdmdfTXBoMi4KCk5ldyBkYXRhc2V0IChOb091dGxpZXJzX1RyYXZlbERpc3ROVGltZSkgd2hlbiByZW1vdmluZyBvdXRsaWVyIGxvdyB2YWx1ZXMgb2YgVHJhdmVsRGlzdGFuY2VfTWlfTmV3IGFuZCBUcmF2ZWxUaW1lX1NlYy4KYGBge3J9CgpWaWV3KFRyYXZEaXN0TWlOZXdfUGN0aWxlcykKVmlldyhUcmF2VGltZUhyX1BjdGlsZXMpCgpOb091dGxpZXJzX1RyYXZlbERpc3ROVGltZSA8LSBmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3ID4gLjA3Nzg0MTAwNSAmICMgNXRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcgPCAxLjA4MTI1MDAwMDAgJiAjIDk5dGggcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYyA+IDEyLjEwMDAwMCAjIDR0aCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVHJhdmVsVGltZV9TZWMgPCAyOTMuMDAwMDAwICMgOTh0aCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCm5yb3coQWxsRGF5c19OZXdUcmF2ZWxEaXN0KSAtIG5yb3coTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUpCgpzdHIoTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUpCnN1bW1hcnkoTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUpCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFNwcGVkQXZnX01waDIuCgpWaWV3KFNwZWVkX05vT3V0X1BjdGlsZXMpOiAgQXByb3hpbWF0ZWx5IDkwJSBvZiBTcGVlZEF2Z19NcGgyIHZhbHVlcyBhcmUgYmV0d2VlbiB+NG1waCBhbmQgfjU2bXBoLgpgYGB7cn0KClNwZWVkX05vT3V0X050aWxlIDwtIGFzLmRhdGEuZnJhbWUoTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUkU3BlZWRBdmdfTXBoMikgJT4lIAogIG11dGF0ZShQY3RpbGUgPSBudGlsZShOb091dGxpZXJzX1RyYXZlbERpc3ROVGltZSRTcGVlZEF2Z19NcGgyLCAxMDApLAogICAgICAgICBNaW5SID0gbWluX3JhbmsoTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUkU3BlZWRBdmdfTXBoMiksCiAgICAgICAgIFBjdFIgPSBwZXJjZW50X3JhbmsoTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUkU3BlZWRBdmdfTXBoMiksCiAgICAgICAgIFBjdFJfUm91bmQgPSByb3VuZChQY3RSLCAyKQogICAgICAgICkgCgpjb2xuYW1lcyhTcGVlZF9Ob091dF9OdGlsZSlbMV0gPC0gIlNwZWVkQXZnX01waDIiCnN0cihTcGVlZF9Ob091dF9OdGlsZSkKClNwZWVkX05vT3V0X050aWxlX1Jvd3MgPC0gbnJvdyhTcGVlZF9Ob091dF9OdGlsZSkKClZpZXcodGFpbChTcGVlZF9Ob091dF9OdGlsZSwgNTAwKSkKCgpTcGVlZF9Ob091dF9QY3RpbGVzIDwtIGdyb3VwX2J5KFNwZWVkX05vT3V0X050aWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHN1bW1hcmlzZSgKICAgIE1pblNwZWVkQXRQY3RpbGUgPSBtaW4oU3BlZWRBdmdfTXBoMiksCiAgICBDbnRzQXRQY3RpbGUgPSBuKCksCiAgICBQY3RzQXRQY3RpbGUgPSBDbnRzQXRQY3RpbGUgLyBTcGVlZF9Ob091dF9OdGlsZV9Sb3dzCiAgKSAlPiUgCiAgbXV0YXRlKEN1bVN1bVBBdFAgPSBjdW1zdW0oUGN0c0F0UGN0aWxlKQogICAgICAgICkKClZpZXcoU3BlZWRfTm9PdXRfUGN0aWxlcykKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgU3BwZWRBdmdfTXBoMi4KCkV4bG9yaW5nIG9kZC9pbXBvc3NpYmxlIHZhbHVlcy4KYGBge3J9CgojIEV4cGxvcmluZyB3aGVuIFNwZWVkQXZnX01waDIgaXMgTkEgIC0tICBkb2VzIG5vdCBvY2N1ciBhdCBhbGwKbnJvdyhmaWx0ZXIoTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUsCiAgICAgICAgICAgIGlzLm5hKFNwZWVkQXZnX01waDIpCiAgICAgICAgICAgKQogICAgKQoKCiMgRXhwbG9yaW5nIHdoZW4gU3BlZWRBdmdfTXBoMiBpcyB6ZXJvICAtLSAgZG9lcyBub3Qgb2NjdXIgYXQgYWxsCm5yb3coZmlsdGVyKE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lLAogICAgICAgICAgICBTcGVlZEF2Z19NcGgyID09IDAKICAgICAgICAgICApCiAgICApCgoKIyBleGFtcGxlcyB3aGVyZSBTcGVlZEF2Z19NcGgyIDwgMy4yODQ4NzcwClZpZXcoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgU3BlZWRBdmdfTXBoMiA+IDAgJgogICAgICAgICAgICAgIFNwZWVkQXZnX01waDIgPCAzLjI4NDg3NzAKICAgICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoU3BlZWRBdmdfTXBoMikKICAgICkKCiMgZXhhbXBsZXMgd2hlcmUgU3BlZWRBdmdfTXBoMiA8IDMuMjg0ODc3MApWaWV3KGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gNDg1MzM4ICYgUm93TnVtX09HIDw9IDQ4NTM1OCkgfCAjIDQ4NTM0OCAgLS0gIEV4dHJlbWUgdHJhdmVsIHRpbWUsIFJvdXRlIENoYW5nZQogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAzNDY5NTIgJiBSb3dOdW1fT0cgPD0gMzQ2OTcyKSB8ICMgMzQ2OTYyICAtLSBFeHRyZW1lIHRyYXZlbCB0aW1lLCBSb3V0ZSBDaGFuZ2UgCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDcwNDk0ICYgUm93TnVtX09HIDw9IDcwNTE0KSB8ICMgNzA1MDQgIC0tICBFeHRyZW1lIHRyYXZlbCB0aW1lLCBSb3V0ZSBDaGFuZ2UKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjA1MTg0NiAmIFJvd051bV9PRyA8PSAyMDUxODY2KSAjIDIwNTE4NTYgIC0tICBFeHRyZW1lIHRyYXZlbCB0aW1lLCBSb3V0ZSBDaGFuZ2UKICAgICAgICAgICApCiAgICApCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFNwZWVkQXZnX01waDIuCgpMaW1pdCB0aGUgZGF0YXNldCBiYXNlZCBvbiBTcGVlZEF2Z19NcGgyLgpgYGB7cn0KCk5vT3V0bGllcnNTcGVlZCA8LSBmaWx0ZXIoTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYmV0d2VlbihTcGVlZEF2Z19NcGgyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNC4wNjkzMDAsICMgNXRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDU2LjA1NjUxICM5NXRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICkKCm5yb3coTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUpIC0gbnJvdyhOb091dGxpZXJzU3BlZWQpCgpzdW1tYXJ5KE5vT3V0bGllcnNTcGVlZCkKCmBgYAoKClRyYXZlbFRpbWUgbm93IGxvb2tzIGxpa2UgaXQgaGFzIHNvbWUgb2RkIHZhbHVlcyBvbiB0aGUgaGlnaCBlbmQuICBTbyBsZXQncyBsb29rIGF0IHRob3NlLgoKVmlldyhUcmF2VGltZV9Ob091dF9QY3RpbGVzKTogIFZpcnR1YWxseSBhbGwgdHJpcHMgc2hvdWxkIHRha2UgbGVzcyB0aGFuIDUgbWludXRlcy4gKFRoZSA5OXRoIHBlcmNlbnRpbGUgb2Ygb2YgVHJhdmVsVGltZSBpcyBhcHByb3hpbWF0ZWx5IDggbWludXRlcy4pCmBgYHtyfQoKVHJhdlRpbWVfTm9PdXRfTnRpbGUgPC0gYXMuZGF0YS5mcmFtZShOb091dGxpZXJzU3BlZWQkVHJhdmVsVGltZV9IcikgJT4lIAogIG11dGF0ZShQY3RpbGUgPSBudGlsZShOb091dGxpZXJzU3BlZWQkVHJhdmVsVGltZV9IciwgMTAwKSwKICAgICAgICAgTWluUiA9IG1pbl9yYW5rKE5vT3V0bGllcnNTcGVlZCRUcmF2ZWxUaW1lX0hyKSwKICAgICAgICAgUGN0UiA9IHBlcmNlbnRfcmFuayhOb091dGxpZXJzU3BlZWQkVHJhdmVsVGltZV9IciksCiAgICAgICAgIFBjdFJfUm91bmQgPSByb3VuZChQY3RSLCAyKQogICAgICAgICkKCmNvbG5hbWVzKFRyYXZUaW1lX05vT3V0X050aWxlKVsxXSA8LSAiVHJhdmVsVGltZV9IciIKc3RyKFRyYXZUaW1lX05vT3V0X050aWxlKQoKVHJhdlRpbWVfTm9PdXRfTnRpbGVfUm93cyA8LSBucm93KFRyYXZUaW1lX05vT3V0X050aWxlKQoKVmlldyh0YWlsKFRyYXZUaW1lX05vT3V0X050aWxlLCA1MDApKQoKClRyYXZUaW1lX05vT3V0X1BjdGlsZXMgPC0gZ3JvdXBfYnkoVHJhdlRpbWVfTm9PdXRfTnRpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUGN0Ul9Sb3VuZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgTWluVHJhdlRpbWVIckF0UGN0aWxlID0gbWluKFRyYXZlbFRpbWVfSHIpLAogICAgQ250c0F0UGN0aWxlID0gbigpLAogICAgUGN0c0F0UGN0aWxlID0gQ250c0F0UGN0aWxlIC8gVHJhdlRpbWVfTm9PdXRfTnRpbGVfUm93cwogICkgJT4lIAogIG11dGF0ZShDdW1TdW1QQXRQID0gY3Vtc3VtKFBjdHNBdFBjdGlsZSksCiAgICAgICAgIE1pblRyYXZUaW1lU2VjQXRQY3RpbGUgPSBNaW5UcmF2VGltZUhyQXRQY3RpbGUgKiAoNjAgKiA2MCkKICAgICAgICApCgpWaWV3KFRyYXZUaW1lX05vT3V0X1BjdGlsZXMpCgpgYGAKCgpJbnZlc3RpZ2F0aW5nIG9kZCBUcmF2ZWxUaW1lX1NlYyB2YWx1ZXMuCgpUcmlwcyBsb25nZXIgdGhhbiB+OCBtaW51dGVzLgpgYGB7cn0KClZpZXcoZmlsdGVyKE5vT3V0bGllcnNTcGVlZCwKICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPiA0OTEgIyBtaW4gYXQgdGhlIDEwMHRoIHBlcmNlbnRpbGUKICAgICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoZGVzYyhUcmF2ZWxUaW1lX1NlYykKICAgICAgICAgICAgICApCiAgICApCgojIGV4YW1wbGVzIG9mIFRyYXZlbFRpbWVfU2VjIHZhbHVlcyB0aGF0IGFyZSBsYXJnZXN0LgpWaWV3KGZpbHRlcihOb091dGxpZXJzU3BlZWQsCiAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjA3MTc1OSAmIFJvd051bV9PRyA8PSAyMDcxNzc5KSB8ICMgMjA3MTc2OSAgLS0gIHJlc3VsdHMgZnJvbSBhIHJvdXRlIGNoYW5nZSwgYW5kIGEgM2hyKyB3YWl0IGJlZm9yZSB0aGUgbmV3IHJvdXRlIHN0YXJ0cwogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAxNDczNjg2ICYgUm93TnVtX09HIDw9IDE0NzM3MDYpIHwgIyAxNDczNjk2ICAtLSAgcmVzdWx0cyBmcm9tIGEgcm91dGUgY2hhbmdlLCBhbmQgYSAzaHIgd2FpdCBiZWZvcmUgdGhlIG5ldyByb3V0ZSBzdGFydHMKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMTIyMjgyMiAmIFJvd051bV9PRyA8PSAxMjIyODQyKSB8ICMgMTIyMjgzMiAgLS0gIHJlc3VsdHMgZnJvbSBhIHJvdXRlIGNoYW5nZSwgYW5kIGEgM2hyIHdhaXQgYmVmb3JlIHRoZSBuZXcgcm91dGUgc3RhcnRzCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDMwNDYwODkgJiBSb3dOdW1fT0cgPD0gMzA0NjEwOSkgIyAzMDQ2MDk5ICAtLSAgcmVzdWx0cyBmcm9tIGEgcm91dGUgY2hhbmdlLCBhbmQgYSAzaHIgd2FpdCBiZWZvcmUgdGhlIG5ldyByb3V0ZSBzdGFydHMKICAgICAgICAgICApCiAgICApCgoKIyBleGFtcGxlcyBvZiBUcmF2ZWxUaW1lX1NlYyB2YWx1ZXMgdGhhdCBhcmUgdGhlIHNtYWxsZXN0IG9mIHRoZSBsYXJnZS4KVmlldyhmaWx0ZXIoTm9PdXRsaWVyc1NwZWVkLAogICAgICAgICAgICAoUm93TnVtX09HID49IDMwNDQ2ODkgJiBSb3dOdW1fT0cgPD0gMzA0NDcwOSkgfCAjIDMwNDQ2OTkgIC0tICByZXN1bHRzIGZyb20gYSByb3V0ZSBjaGFuZ2UKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMzAyMjM1OCAmIFJvd051bV9PRyA8PSAzMDIyMzc4KSB8ICMgMzAyMjM2OCAgLS0gIHJlc3VsdHMgZnJvbSBhIHJvdXRlIGNoYW5nZQogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAyOTkzMDE2ICYgUm93TnVtX09HIDw9IDI5OTMwMzYpIHwgIyAyOTkzMDI2ICAtLSAgcmVzdWx0cyBmcm9tIGEgcHJldmlvdXMgcm91dGUgY2hhbmdlIChjaGFuZ2Ugb2NjdXJyZWQgaW4gZGVsZXRlZCByb3cpCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDI2ODM3MDMgJiBSb3dOdW1fT0cgPD0gMjY4MzcyMykgIyAyNjgzNzEzICAtLSAgcmVzdWx0cyBmcm9tIGEgcHJldmlvdXMgcm91dGUgY2hhbmdlIChjaGFuZ2Ugb2NjdXJyZWQgaW4gZGVsZXRlZCByb3cpCiAgICAgICAgICAgKQogICAgKQoKYGBgCgoKTGV0J3MgbG9vayBhdCB0aGUgVHJhdmVsVGltZV9TZWMgdmFsdWVzIGFuZCByb3V0ZSBjaGFuZ2VzIChEaXJDaGFuZ2UyKS4KClRoZSA5OXRoIHBlcmNlbnRpbGUgb2YgVHJhdmVsVGltZV9TZWMgZm9yIGJvdGgsIGFsbCB0cmlwcywgYW5kIGp1c3QgdGhvc2UgdHJpcHMgTk9UIGludm9sdmluZyByb3V0ZSBjaGFuZ2VzIChEaXJDaGFuZ2UyID0gIlNhbWUiKSwgaXMgYXBwcm94aW1hdGVseSA1bWluICgzMDAgc2VjKS4KCk5vdGEgQmVuZTogIFRoZSBwZXJjZW50aWxlIGNhbGN1bGF0aW9uIGhlcmUgaXMgZGVmaW5lZCBzbGlnaHRseSBkaWZmZXJlbnQgdGhhbiBpbiBtb3N0IG9mIHRoZSBhYm92ZSBhbmFseXNlcyAod2hpY2ggZ2V0IHRoZSBsb3dlc3QgdmFsdWUgaW4gdGhlIGJpbiBjcmVhdGVkIGJ5IDEwMCBudGlsZXMpLgpgYGB7cn0KCnN1bW1hcnkoc2VsZWN0KE5vT3V0bGllcnNTcGVlZCwKICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMKICAgICAgICAgICAgICApCiAgICAgICApCgpzdW1tYXJ5KHNlbGVjdChmaWx0ZXIoTm9PdXRsaWVyc1NwZWVkLAogICAgICAgICAgICAgICAgICAgICAgRGlyQ2hhbmdlMiA9PSAiU2FtZSIKICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMKICAgICAgICAgICAgICApCiAgICAgICApCgpzdW1tYXJ5KHNlbGVjdChmaWx0ZXIoTm9PdXRsaWVyc1NwZWVkLAogICAgICAgICAgICAgICAgICAgICAgRGlyQ2hhbmdlMiA9PSAiQ2hhbmdlIgogICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYwogICAgICAgICAgICAgICkKICAgICAgICkKCgpUcmF2VGltZVNlY19RdGlsZXNfZGYgPC0gZGF0YS5mcmFtZShQY3RWYWx1ZSA9IHNlcSgwLCAxMDAsIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbGwgPSBzZXEoMSwgMTAxLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2FtZSA9IHNlcSgxLCAxMDEsIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDaGFuZ2UgPSBzZXEoMSwgMTAxLCAxKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKClRyYXZUaW1lU2VjX1F0aWxlc19kZlsgLCAyXSA8LSBxdWFudGlsZShzZWxlY3QoTm9PdXRsaWVyc1NwZWVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYnMgPSBzZXEoMCwgMSwgMC4wMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKVHJhdlRpbWVTZWNfUXRpbGVzX2RmWyAsIDNdIDwtIHF1YW50aWxlKHNlbGVjdChmaWx0ZXIoTm9PdXRsaWVyc1NwZWVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaXJDaGFuZ2UyID09ICJTYW1lIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icyA9IHNlcSgwLCAxLCAwLjAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpUcmF2VGltZVNlY19RdGlsZXNfZGZbICwgNF0gPC0gcXVhbnRpbGUoc2VsZWN0KGZpbHRlcihOb091dGxpZXJzU3BlZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpckNoYW5nZTIgPT0gIkNoYW5nZSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYnMgPSBzZXEoMCwgMSwgMC4wMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKVmlldyhUcmF2VGltZVNlY19RdGlsZXNfZGYpCgpgYGAKCgpMaW1pdCB0aGUgZGF0YXNldCBub3cgYmFzZWQgb24gVHJhdmVsVGltZV9TZWMuCmBgYHtyfQoKVXBwZXJMaW1pdFRyYXZUaW1lIDwtIGZpbHRlcihOb091dGxpZXJzU3BlZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPD0gNDkxICMgbWluIGF0IHRoZSAxMDB0aCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKbnJvdyhOb091dGxpZXJzU3BlZWQpIC0gbnJvdyhVcHBlckxpbWl0VHJhdlRpbWUpCgpzdHIoVXBwZXJMaW1pdFRyYXZUaW1lKQoKc3VtbWFyeShVcHBlckxpbWl0VHJhdlRpbWUpCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIER3ZWxsX1RpbWUyIChob3cgbG9uZyB0aGUgYnVzIGlzIGF0IGEgc3RvcCkuCgpEaWZmZXJlbmNlcyBiZXR3ZWVuIER3ZWxsX1RpbWUgKGJ5IFdNQVRBKSBhbmQgRHdlbGxfVGltZTIgKGJ5IG1lKSBhcHBlYXIgdG8gYmUgZHVlIHRvIHN3aXRjaGVzIGluIFJvdXRlQWx0LiBXTUFUQSBjYWxjdWxhdGVzIER3ZWxsX1RpbWUgYnkgYW4gdW5rbm93biBwcm9jZXNzLiBUaGUgV01BVEEgY2FsY3VsYXRpb24gaXMgZXF1YWwgdG8gbXkgY2FsY3VsYXRpb24sIGV4Y2VwdCBmb3IgdGhlIHJlY29yZHMgaW1tZWRhaXRlbHkgYmVmb3JlIGFuZCBhZnRlciBhIFJvdXRlQWx0IHN3aXRjaCAoRGlyQ2hhbmdlMikuCmBgYHtyfQoKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgRHdlbGxfVGltZSAhPSBEd2VsbF9UaW1lMgogICAgICAgICAgICkKICAgICkKCgojIEV4YW1wbGVzIHdoZXJlIHRoZSBEd2VsbF9UaW1lIGFuZCBEd2VsbF9UaW1lMiBhcmUgZGlmZmVyZW50ClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICggKFJvd051bV9PRyA+PSA2NSAmIFJvd051bV9PRyA8PSA4NSkgfCAjIDc1CiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDE2MiAmIFJvd051bV9PRyA8PSAxOTIpIHwgIyAxNzIKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gNDMxOTUyICYgUm93TnVtX09HIDw9IDQzMTk3MikgfCAjIDQzMTk2MgogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSA0MzQ1OTUgJiBSb3dOdW1fT0cgPD0gNDM0NjE1KSAjIDQzNDYwNSAgLS0gIHRoaXMgcmVjb3JkIGlzIE5PVCBhIHJvdXRlIHN3aXRjaCwgYnV0IGRvZXMgaGFzIGEgU2VxdWVuY2Ugc3dpdGNoIChNZTogc2hvdWxkIHRoZXJlIHJlYWxseSBiZSBhIHJvdXRlIHN3aXRjaCBoZXJlPykKICAgICAgICAgICAgKQogICAgICAgICAgICkKICAgICkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgRHdlbGxfVGltZTIgKGhvdyBsb25nIHRoZSBidXMgaXMgYXQgYSBzdG9wKS4KCkZpcnN0LCBjcmVhdGUgc29tZSAicmFuayIgc3RhdHMuClZpZXcoRFQyX1BjdGlsZXMpOiA5NSUgb2YgRHdlbGxfVGltZTJzIGFyZSA8PSAyMyBzZWNvbmRzLi4uYnV0IHNvbWUgd2VpcmQgKGUuZy4sIG5lYXJseSAyIGhvdXIgRHdlbGxfVGltZTJzIGV4aXN0KS4KYGBge3J9CgpEd2VsbFRpbWUyX050aWxlIDwtIGFzLmRhdGEuZnJhbWUoQWxsRGF5c19OZXdPcmRlciREd2VsbF9UaW1lMikgJT4lIAogIG11dGF0ZShQY3RpbGUgPSBudGlsZShBbGxEYXlzX05ld09yZGVyJER3ZWxsX1RpbWUyLCAxMDApLAogICAgICAgICBNaW5SID0gbWluX3JhbmsoQWxsRGF5c19OZXdPcmRlciREd2VsbF9UaW1lMiksCiAgICAgICAgIFBjdFIgPSBwZXJjZW50X3JhbmsoQWxsRGF5c19OZXdPcmRlciREd2VsbF9UaW1lMiksCiAgICAgICAgIFBjdFJfUm91bmQgPSByb3VuZChQY3RSLCAyKQogICAgICAgICkgCgpjb2xuYW1lcyhEd2VsbFRpbWUyX050aWxlKVsxXSA8LSAiRHdlbGxfVGltZTIiCnN0cihEd2VsbFRpbWUyX050aWxlKQoKRHdlbGxUaW1lMl9OdGlsZV9Sb3dzIDwtIG5yb3coRHdlbGxUaW1lMl9OdGlsZSkKClZpZXcodGFpbChEd2VsbFRpbWUyX050aWxlLCA1MDApKQoKCkR3ZWxsVGltZTJfUGN0aWxlcyA8LSBncm91cF9ieShEd2VsbFRpbWUyX050aWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUGN0Ul9Sb3VuZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzdW1tYXJpc2UoCiAgICBNaW5Ed2VsbEF0UGN0aWxlID0gbWluKER3ZWxsX1RpbWUyKSwKICAgIENudHNBdFBjdGlsZSA9IG4oKSwKICAgIFBjdHNBdFBjdGlsZSA9IENudHNBdFBjdGlsZSAvIER3ZWxsVGltZTJfTnRpbGVfUm93cwogICkgJT4lIAogIG11dGF0ZShDdW1TdW1QQXRQID0gY3Vtc3VtKFBjdHNBdFBjdGlsZSkKICAgICAgICApCgpWaWV3KER3ZWxsVGltZTJfUGN0aWxlcykKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgRHdlbGxfVGltZTIgKGhvdyBsb25nIHRoZSBidXMgaXMgYXQgYSBzdG9wKS4KCkhpc3RvZ3JhbSBvZiBEd2VsbF9UaW1lMi4KYGBge3J9CgpEd2VsbFRpbWUyX0hpc3REZW4gPC0gZ2dwbG90KEFsbERheXNfTmV3T3JkZXIsIGFlcyh4ID0gRHdlbGxfVGltZTIsIHkgPSAuLmRlbnNpdHkuLikpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3VyID0gImdyZXk2MCIsIHNpemUgPSAwLjIpICsKICBnZW9tX2xpbmUoc3RhdCA9ICJkZW5zaXR5IiwgY29sb3VyID0gInJlZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMSwgMjUpLCB5bGltID0gYygwLCAwLjA1KQogICAgICAgICAgICAgICAgICkgKwogIHhsYWIoIlRpbWUgYSBCdXMgU3RheXMgYXQgYSBTdG9wIChzZWMpIikgKyAKICB5bGFiKCJEZW5zaXR5IikgKyAKICAjICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIAogIGdndGl0bGUoZXhwcmVzc2lvbihhdG9wKCJWYXJpYXRpb24gaW4gSG93IExvbmcgYSBCdXMgU3RheXMgYXQgYSBTdG9wIgogICAgICAgICAgICAgICAgICAgICAgICAgICMgLGF0b3AoaXRhbGljKCJ4eHh4eCIpLCIiKQogICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgKQoKRHdlbGxUaW1lMl9IaXN0RGVuCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIER3ZWxsX1RpbWUyIChob3cgbG9uZyB0aGUgYnVzIGlzIGF0IGEgc3RvcCkuCgpMb29raW5nIGF0IHNvbWUgd2VpcmRseSBsb25nIER3ZWxsX1RpbWUyIHZhbHVlcy4KYGBge3J9CgpWaWV3KGFycmFuZ2UoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgIGRlc2MoRHdlbGxfVGltZTIpCiAgICAgICAgICAgICkKICAgICkKCgojIGV4YW1wbGVzIG9mIGV4dHJlbWVseSBsYXJnZSBEd2VsbF9UaW1lMnMKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgKFJvd051bV9PRyA+PSAyOTI2NjkgJiBSb3dOdW1fT0cgPD0gMjkyNjg5KSB8ICMgMjkyNjc5CiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDUzMTA1NyAmIFJvd051bV9PRyA8PSA1MzEwNzcpIHwgIyA1MzEwNjcKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMTM4ODYyNyAmIFJvd051bV9PRyA8PSAxMzg4NjQ3KSB8ICMgMTM4ODYzNwogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAxNjQ1NzExICYgUm93TnVtX09HIDw9IDE2NDU3MzEpICMgMTY0NTcyMQogICAgICAgICAgICkKICAgICkKCgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBEd2VsbF9UaW1lMiA9PSAwCiAgICAgICAgICAgKQogICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBEZWx0YV9UaW1lIChob3cgZWFybHkgb3IgbGF0ZSB0aGUgYnVzIGlzKS4KClZpZXcoRFQyX1BjdGlsZXMpOiA5NCUgb2YgRGVsdGFfVGltZSB2YWx1ZXMgYXJlIGJldHdlZW4gLTIzNiBzZWNvbmRzIGFuZCAxLDI1OSBzZWNvbmRzLiBSb3VnaGx5IDY2JSBvZiByZWNvcmRzIGFyZSB3aXRoaW4gNSBtaW4gbGF0ZSBhbmQgNSBtaW4gZWFybHkuLi5idXQgc29tZSB3ZWlyZCAoZS5nLiwgYWxtb3N0IDUwIG1pbnV0ZSBsYXRlIG9yIDQwIG1pbnV0ZSBlYXJseSkgRGVsdGFfVGltZXMgZXhpc3QuCgpOb3RlIHRoYXQgRGVsdGFfVGltZSBpcyB0aGUgZGlmZmVyZW5jZSBmcm9tIHRoZSBzY2hlZHVsZWQgYnVzIGFycml2YWwuIFNvIGlmIHR3byBidXNlcyBhcmUgc2NoZWR1bGVkIHRvIGFycml2ZSBhdCBhIGRlc3RpbmF0aW9uIGF0IDEwOjAwcG0gYW5kIDEwOjIwcG0sIGFuZCBpZiB0aGUgMTA6MjBwbSBidXMgaGFzIGEgRGVsdGFfVGltZSBvZiA1IG1pbnV0ZXMsIHRoZXJlIGFyZSAyNSBtaW51dGVzIGJldHdlZW4gYnVzIGFycml2YWxzIGF0IHRoZSBzdG9wLgoKQWxzbyBub3RlIHRoYXQgYmFzZWQgb24gYSBjb21tZW50IGF0IGh0dHBzOi8vcGxhbml0bWV0cm8uY29tLzIwMTYvMTEvMTYvZGF0YS1kb3dubG9hZC1tZXRyb2J1cy12ZWhpY2xlLWxvY2F0aW9uLWRhdGEvLCB0aGUgRGVsdGFfVGltZSB2YWx1ZXMgZG9uJ3QgYXBwZWFyIHRvIGNvaW5jaWRlIHdpdGggcHVibGlzaGVkIGJ1cyBzY2hlZHVsZXMgKGUuZy4sIHRoZSBYMiBkZXBhcnRpbmcgZXZlcnkgOCBtaW51dGVzIGR1cmluZyBwZWFrIGhvdXJzKS4KYGBge3J9CgpEZWx0VGltZV9OdGlsZSA8LSBhcy5kYXRhLmZyYW1lKEFsbERheXNfTmV3T3JkZXIkRGVsdGFfVGltZSkgJT4lIAogIG11dGF0ZShQY3RpbGUgPSBudGlsZShBbGxEYXlzX05ld09yZGVyJERlbHRhX1RpbWUsIDEwMCksCiAgICAgICAgIE1pblIgPSBtaW5fcmFuayhBbGxEYXlzX05ld09yZGVyJERlbHRhX1RpbWUpLAogICAgICAgICBQY3RSID0gcGVyY2VudF9yYW5rKEFsbERheXNfTmV3T3JkZXIkRGVsdGFfVGltZSksCiAgICAgICAgIFBjdFJfUm91bmQgPSByb3VuZChQY3RSLCAyKQogICAgICAgICkgCgpjb2xuYW1lcyhEZWx0VGltZV9OdGlsZSlbMV0gPC0gIkRlbHRhX1RpbWUiCnN0cihEZWx0VGltZV9OdGlsZSkKCkRlbHRUaW1lX050aWxlX1Jvd3MgPC0gbnJvdyhEZWx0VGltZV9OdGlsZSkKClZpZXcodGFpbChEZWx0VGltZV9OdGlsZSwgNTAwKSkKCgpEZWx0VGltZV9QY3RpbGVzIDwtIGdyb3VwX2J5KERlbHRUaW1lX050aWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHN1bW1hcmlzZSgKICAgIE1pbkRlbHRUaW1lQXRQY3RpbGUgPSBtaW4oRGVsdGFfVGltZSksCiAgICBDbnRzQXRQY3RpbGUgPSBuKCksCiAgICBQY3RzQXRQY3RpbGUgPSBDbnRzQXRQY3RpbGUgLyBEZWx0VGltZV9OdGlsZV9Sb3dzCiAgKSAlPiUgCiAgbXV0YXRlKEN1bVN1bVBBdFAgPSBjdW1zdW0oUGN0c0F0UGN0aWxlKQogICAgICAgICkKClZpZXcoRGVsdFRpbWVfUGN0aWxlcykKRGVsdFRpbWVfUGN0aWxlcwoKIyB+NjYlIG9mIHJvd3MgYXJlIGJldHdlZW4gNSBtaW4gbGF0ZSBhbmQgNSBtaW4gZWFybHkKbnJvdyhmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgRGVsdGFfVGltZSA+PSAtMzAwICYKICAgICAgICAgICAgICBEZWx0YV9UaW1lIDw9IDMwMAogICAgICAgICAgICkKICAgICkgLyBucm93KEFsbERheXNfTmV3T3JkZXIpCgoKIyBleGFtcGxlcyBvZiB3ZWlyZCBsYXJnZSBEZWx0YV9UaW1lcwpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBEZWx0YV9UaW1lIDwgLTQyMDIgfAogICAgICAgICAgICAgIERlbHRhX1RpbWUgPiAxNzA1CiAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKGRlc2MoRGVsdGFfVGltZSkKICAgICAgICAgICAgICApCiAgICApCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIERlbHRhX1RpbWUgKGhvdyBlYXJseSBvciBsYXRlIHRoZSBidXMgaXMpLgoKRGVsdGFfVGltZSBoaXN0b2dyYW0uCmBgYHtyfQoKRGVsdFRpbWVfSGlzdERlbiA8LSBnZ3Bsb3QoQWxsRGF5c19OZXdPcmRlciwgYWVzKHggPSAoRGVsdGFfVGltZSAvIDYwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAuLmRlbnNpdHkuLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAoNS82MCksIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3VyID0gImdyZXk2MCIsIHNpemUgPSAwLjIpICsKICBnZW9tX2xpbmUoc3RhdCA9ICJkZW5zaXR5IiwgY29sb3VyID0gInJlZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoLTUsIDUpKSArCiAgeGxhYigiQnVzIExhdGVuZXNzIChtaW4pIikgKyAKICB5bGFiKCJEZW5zaXR5IikgKyAKICAjICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIAogIGdndGl0bGUoZXhwcmVzc2lvbihhdG9wKCJWYXJpYXRpb24gaW4gSG93IEVhcmx5L0xhdGUgYSBCdXMgSXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGF0b3AoaXRhbGljKCIocG9zaXRpdmUgdmFsdWVzIGFyZSBsYXRlIGFycml2YWxzKSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgKQoKRGVsdFRpbWVfSGlzdERlbgoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBEZWx0YV9UaW1lIChob3cgZWFybHkgb3IgbGF0ZSB0aGUgYnVzIGlzKS4KCkRlbHRhX1RpbWUgYm94cGxvdC4KYGBge3J9CgojIENvdW50X1ZhbHVlcyBpcyBuZWVkZWQgdG8gZGlzcGxheSB0aGUgbWVkaWFucyBvbiB0aGUgYm94IHBsb3RzCkNvdW50X1ZhbHVlcyA8LSBkZHBseShBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICAgICAgICAgICAgLihFdmVudF9UaW1lX0hyR3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlLAogICAgICAgICAgICAgICAgICAgICAgVmFsdWVfQ291bnRzID0gbWVkaWFuKERlbHRhX1RpbWUgLyA2MCwgbmEucm0gPSBUUlVFKQogICAgICAgICAgICAgICAgICAgICApCgpEZWx0VGltZV9Cb3hQbG90IDwtIGdncGxvdChBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoZmFjdG9yKEV2ZW50X1RpbWVfSHJHcm91cCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWx0YV9UaW1lIC8gNjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZmFjdG9yKEV2ZW50X1RpbWVfSHJHcm91cCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICkgKyAKICBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9InJlZCIsIG5vdGNoPVRSVUUpICsgCiAgIyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTMwMCwgMTIwMCkpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTUsIDIwKSkgKwogIGdlb21fdGV4dChkYXRhID0gQ291bnRfVmFsdWVzLAogICAgICAgICAgICBhZXMoeSA9IFZhbHVlX0NvdW50cywKICAgICAgICAgICAgICAgIGxhYmVsID0gZm9ybWF0KHJvdW5kKFZhbHVlX0NvdW50cywgZGlnaXRzID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc21hbGwgPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNQogICAgICAgICAgICkgKwogIHhsYWIoIkhvdXIgR3JvdXAiKSArIAogIHlsYWIoIkJ1cyBMYXRlbmVzcyAobWludXRlcykiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1KSkgKyAKICAjdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJyaWdodCIsIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArIAogIGdndGl0bGUoZXhwcmVzc2lvbihhdG9wKCJIb3cgRWFybHkvTGF0ZSBpcyB0aGUgQnVzIChieSBIb3VyIEdyb3VwKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXRvcChpdGFsaWMoIihwb3NpdGl2ZSB2YWx1ZXMgYXJlIGxhdGUgYXJyaXZhbHMpIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICApCgpEZWx0VGltZV9Cb3hQbG90CgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIERlbHRhX1RpbWUgKGhvdyBlYXJseSBvciBsYXRlIHRoZSBidXMgaXMpLgoKRXhwbG9yaW5nICJleHRyZW1lIiBEZWx0YV9UaW1lcy4gIEZpcnN0IGxldCdzIGdldCBzb21lICJyYW5rIiBzdGF0cy4KYGBge3J9CgpWaWV3KERlbHRUaW1lX1BjdGlsZXMpCkRlbHRUaW1lX1BjdGlsZXMKCgpEZWx0VGltZUFic19OdGlsZSA8LSBhcy5kYXRhLmZyYW1lKGFicyhBbGxEYXlzX05ld09yZGVyJERlbHRhX1RpbWUpKSAlPiUgCiAgbXV0YXRlKFBjdGlsZSA9IG50aWxlKGFicyhBbGxEYXlzX05ld09yZGVyJERlbHRhX1RpbWUpLCAxMDApLAogICAgICAgICBNaW5SID0gbWluX3JhbmsoYWJzKEFsbERheXNfTmV3T3JkZXIkRGVsdGFfVGltZSkpLAogICAgICAgICBQY3RSID0gcGVyY2VudF9yYW5rKGFicyhBbGxEYXlzX05ld09yZGVyJERlbHRhX1RpbWUpKSwKICAgICAgICAgUGN0Ul9Sb3VuZCA9IHJvdW5kKFBjdFIsIDIpCiAgICAgICAgKSAKCmNvbG5hbWVzKERlbHRUaW1lQWJzX050aWxlKVsxXSA8LSAiRGVsdGFfVGltZV9BYnMiCnN0cihEZWx0VGltZUFic19OdGlsZSkKCkRlbHRUaW1lQWJzX050aWxlX1Jvd3MgPC0gbnJvdyhEZWx0VGltZUFic19OdGlsZSkKClZpZXcodGFpbChEZWx0VGltZUFic19OdGlsZSwgNTAwKSkKCgpEZWx0VGltZUFic19QY3RpbGVzIDwtIGdyb3VwX2J5KERlbHRUaW1lQWJzX050aWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHN1bW1hcmlzZSgKICAgIE1pbkRlbHRUaW1lQXRQY3RpbGUgPSBtaW4oRGVsdGFfVGltZV9BYnMpLAogICAgQ250c0F0UGN0aWxlID0gbigpLAogICAgUGN0c0F0UGN0aWxlID0gQ250c0F0UGN0aWxlIC8gRGVsdFRpbWVfTnRpbGVfUm93cwogICkgJT4lIAogIG11dGF0ZShDdW1TdW1QQXRQID0gY3Vtc3VtKFBjdHNBdFBjdGlsZSkKICAgICAgICApCgpWaWV3KERlbHRUaW1lQWJzX1BjdGlsZXMpCkRlbHRUaW1lQWJzX1BjdGlsZXMKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgRGVsdGFfVGltZSAoaG93IGVhcmx5IG9yIGxhdGUgdGhlIGJ1cyBpcykuCgpFeHBsb3JpbmcgImV4dHJlbWUiIERlbHRhX1RpbWVzLiAgVGhlbiBsZXQncyBjYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2Ugb2YgYnVzZXMgdGhhdCBhcmUgMTAgbWludXRlcyAob3IgbW9yZSkgbGF0ZS9lYXJseS4KYGBge3J9CgpIckdyb3VwX0RlbHRhVGltZV9BbGwgPC0gZ3JvdXBfYnkoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfSHJHcm91cAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzdW1tYXJpc2UoRXZlbnRBbGxfQ250ID0gbigpCiAgICAgICAgICAgKQoKc3RyKEhyR3JvdXBfRGVsdGFUaW1lX0FsbCkKVmlldyhIckdyb3VwX0RlbHRhVGltZV9BbGwpCgoKSHJHcm91cF9EZWx0YVRpbWVfQWJvdmUxME1pbiA8LSBmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWJzKERlbHRhX1RpbWUpID49IDYwMAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIGdyb3VwX2J5KEV2ZW50X1RpbWVfSHJHcm91cCkgJT4lIAogIHN1bW1hcmlzZShFdmVudEFib3ZlMTBfQ250ID0gbigpCiAgICAgICAgICAgKQoKc3RyKEhyR3JvdXBfRGVsdGFUaW1lX0Fib3ZlMTBNaW4pClZpZXcoSHJHcm91cF9EZWx0YVRpbWVfQWJvdmUxME1pbikKCgpIckdyb3VwX0RlbHRhVGltZUNvbXBhcmUgPC0gaW5uZXJfam9pbihIckdyb3VwX0RlbHRhVGltZV9BYm92ZTEwTWluLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBIckdyb3VwX0RlbHRhVGltZV9BbGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiRXZlbnRfVGltZV9Ickdyb3VwIiA9ICJFdmVudF9UaW1lX0hyR3JvdXAiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIG11dGF0ZShQY3RFdmVudHNBYm92ZTEwID0gRXZlbnRBYm92ZTEwX0NudCAvIEV2ZW50QWxsX0NudCkKClZpZXcoSHJHcm91cF9EZWx0YVRpbWVDb21wYXJlKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBEZWx0YV9UaW1lIChob3cgZWFybHkgb3IgbGF0ZSB0aGUgYnVzIGlzKS4KClF1aWNrbHkgcGxvdCB0aGVzZSAiZXh0cmVtZSIgRGVsdGFfVGltZXMuIApgYGB7cn0KCkRlbHRUaW1lX0Fib3ZlMTBfQ29scyA8LSBnZ3Bsb3QoSHJHcm91cF9EZWx0YVRpbWVDb21wYXJlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhmYWN0b3IoRXZlbnRfVGltZV9Ickdyb3VwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUGN0RXZlbnRzQWJvdmUxMAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogIGdlb21fY29sKGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3VyID0gImdyZXk2MCIsIHNpemUgPSAwLjIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gZm9ybWF0KHJvdW5kKFBjdEV2ZW50c0Fib3ZlMTAsIGRpZ2l0cyA9IDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnNtYWxsID0gMgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgICBudWRnZV95ID0gKEhyR3JvdXBfRGVsdGFUaW1lQ29tcGFyZSRQY3RFdmVudHNBYm92ZTEwICogLTAuMSkKICAgICAgICAgICApICsKICAjIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtNSwgNSkpICsKICB4bGFiKCJIb3VyIEdyb3VwIikgKyAKICB5bGFiKCJQZXJjZW50IG9mIEFsbCBCdXMgQXJyaXZhbHMiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUpKSArCiAgZ2d0aXRsZShleHByZXNzaW9uKGF0b3AoIldoZW4gaXMgYSBCdXMgMTArIE1pbnV0ZXMgTGF0ZS9FYXJseSIKICAgICAgICAgICAgICAgICAgICAgICAgICAjICxhdG9wKGl0YWxpYygicG9zaXRpdmUgdmFsdWVzIGFyZSBsYXRlIGFycml2YWxzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgICIiCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgKQoKRGVsdFRpbWVfQWJvdmUxMF9Db2xzCgpgYGAKCgpRdWljayBpbnZlc3RpZ2F0aW9uIG9uIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBEd2VsbF9UaW1lMiAodGhlIHRpbWUgYSBidXMgaXMgYXQgYSBzdG9wKSBhbmQgRGVsdGFfVGltZSAoaG93IGVhcmx5L2xhdGUgdGhlIGJ1cyBpcykuCgpDb3JyZWxhdGlvbi4KYGBge3J9CgpEd2VsbFREZWx0YVRfQ29yciA8LSBhcy5tYXRyaXgoY29yKHggPSBBbGxEYXlzX05ld09yZGVyJER3ZWxsX1RpbWUyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBBbGxEYXlzX05ld09yZGVyJERlbHRhX1RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlID0gInBhaXJ3aXNlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKRHdlbGxURGVsdGFUX0NvcnIKCmBgYAoKClF1aWNrIGludmVzdGlnYXRpb24gb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIER3ZWxsX1RpbWUyICh0aGUgdGltZSBhIGJ1cyBpcyBhdCBhIHN0b3ApIGFuZCBEZWx0YV9UaW1lIChob3cgZWFybHkvbGF0ZSB0aGUgYnVzIGlzKS4KCk5leHQsIGxldCdzIGdldCBhIHNhbXBsZSBvZiBkYXRhIGZvciBwbG90dGluZy4gTGV0J3MgZG8gdGhpcyBmb3IgdGhlIGZ1bGwgZGF0YXNldCAoQWxsRGF5c19OZXdPcmRlcikuCmBgYHtyfQoKQWxsRGF5c19OZXdPcmRlcl8xMFBjdFNhbXAgPC0gc2FtcGxlX2ZyYWMoQWxsRGF5c19OZXdPcmRlciwgMC4xKSAlPiUgCiAgc2VsZWN0KERlbHRhX1RpbWUsCiAgICAgICAgIER3ZWxsX1RpbWUyCiAgICAgICAgKSAlPiUgCiAgbXV0YXRlKERhdGFTZXQgPSAiQWxsRGF0YSIpCgpzdHIoQWxsRGF5c19OZXdPcmRlcl8xMFBjdFNhbXApCgpgYGAKCgpRdWljayBpbnZlc3RpZ2F0aW9uIG9uIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBEd2VsbF9UaW1lMiAodGhlIHRpbWUgYSBidXMgaXMgYXQgYSBzdG9wKSBhbmQgRGVsdGFfVGltZSAoaG93IGVhcmx5L2xhdGUgdGhlIGJ1cyBpcykuCgpMZXQncyBhbHNvIGdldCBhIHNhbXBsZSBvZiBkYXRhIGZvciBwbG90dGluZywgYnV0IHdpdGggYSBkYXRzZXQgdGhhdCByZW1vdmVzIG91dGxpZXJzLgpgYGB7cn0KClZpZXcoRGVsdFRpbWVfUGN0aWxlcykKVmlldyhEd2VsbFRpbWUyX1BjdGlsZXMpCgpBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wIDwtIGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZXR3ZWVuKERlbHRhX1RpbWUsIC00MDIsIDE3MDUpICYgIyByZW1vdmVzIGFib3V0IDIlIG9mIERlbHRhX1RpbWUgdmFsdWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmV0d2VlbihEd2VsbF9UaW1lMiwgMSwgNjMpICAjIHJlbW92ZXMgYWJvdXQgMiUgb2YgRHdlbGxfVGltZTIgdmFsdWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc2FtcGxlX2ZyYWMoMC4xKSAlPiUgCiAgc2VsZWN0KERlbHRhX1RpbWUsCiAgICAgICAgIER3ZWxsX1RpbWUyCiAgICAgICAgKSAlPiUgCiAgbXV0YXRlKERhdGFTZXQgPSAiT3V0bGllcnNSZW1vdmVkIikKCnN0cihBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wKQoKYGBgCgoKUXVpY2sgaW52ZXN0aWdhdGlvbiBvbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gRHdlbGxfVGltZTIgKHRoZSB0aW1lIGEgYnVzIGlzIGF0IGEgc3RvcCkgYW5kIERlbHRhX1RpbWUgKGhvdyBlYXJseS9sYXRlIHRoZSBidXMgaXMpLgoKUGxvdHRpbmcgdGhlIGRhdGEgZnJvbSB0aGUgZGF0YXNldCB0aGF0IGRvZXMgbm90IHJlbW92ZSBvdXRsaWVycy4KYGBge3J9CgpEd2VsbFREZWx0YVRfU2NhdHRlciA8LSBnZ3Bsb3QoQWxsRGF5c19OZXdPcmRlcl8xMFBjdFNhbXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoRHdlbGxfVGltZTIsIERlbHRhX1RpbWUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAxLCBhbHBoYSA9IDAuNSkgKwogIHNjYWxlX3NoYXBlKHNvbGlkID0gRkFMU0UpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvdXIgPSAicmVkIikgKwogICMgeGxhYigiVGltZSBhdCBTdG9wIChzZWMpIikgKyAKICAjIHlsYWIoIkxhdGVuZXNzIChzZWMpIikgKwogIGFubm90YXRlKGxhYmVsID0gbG1fZXFuKGRmID0gQWxsRGF5c19OZXdPcmRlcl8xMFBjdFNhbXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEFsbERheXNfTmV3T3JkZXJfMTBQY3RTYW1wJERlbHRhX1RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IEFsbERheXNfTmV3T3JkZXJfMTBQY3RTYW1wJER3ZWxsX1RpbWUyCiAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIHggPSAyMjAwLAogICAgICAgICAgIHkgPSA2MDAsCiAgICAgICAgICAgZ2VvbSA9ICJ0ZXh0IiwKICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICBjb2xvdXIgPSAicmVkIiwKICAgICAgICAgICBwYXJzZSA9IFRSVUUKICAgICAgICAgICkgKwogIGxhYnModGl0bGUgPSAiTGF0ZW5lc3MgdnMgVGltZSBhdCBTdG9wIiwKICAgICAgIHN1YnRpdGxlID0gIihubyBvdXRsaWVycyByZW1vdmVkKSIsCiAgICAgICB4ID0gIlRpbWUgYXQgU3RvcCAoc2VjKSIsCiAgICAgICB5ID0gIkxhdGVuZXNzIChzZWMpIgogICAgICApCiAgIyBnZ3RpdGxlKGV4cHJlc3Npb24oYXRvcCgiTGF0ZW5lc3MgdnMgVGltZSBhdCBTdG9wIgogICMgICAgICAgICAgICAgICAgICAgICAgICAgLGF0b3AoaXRhbGljKCIobm8gb3V0bGllcnMgcmVtb3ZlZCkiKSwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIiCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAjICAgICAgICAgICAgICAgICAgICAgICAgKQogICMgICAgICAgICAgICAgICAgICAgKQogICMgICAgICAgICkKIyArCiMgICBnZW9tX2ppdHRlcigpCgpEd2VsbFREZWx0YVRfU2NhdHRlcgoKYGBgCgoKUXVpY2sgaW52ZXN0aWdhdGlvbiBvbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gRHdlbGxfVGltZTIgKHRoZSB0aW1lIGEgYnVzIGlzIGF0IGEgc3RvcCkgYW5kIERlbHRhX1RpbWUgKGhvdyBlYXJseS9sYXRlIHRoZSBidXMgaXMpLgoKUGxvdHRpbmcgdGhlIGRhdGEgZnJvbSB0aGUgZGF0YXNldCB0aGF0IGRvZXMgcmVtb3ZlIG91dGxpZXJzLgpgYGB7cn0KCkR3ZWxsVERlbHRhVF9TY2F0dGVyX05vRXh0cmVtZXMgPC0gZ2dwbG90KEFsbERheXNfTmV3T3JkZXJfTm9FeHRyZW1lc18xMFBjdFNhbXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhEd2VsbF9UaW1lMiwgRGVsdGFfVGltZSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBnZW9tX3BvaW50KHNoYXBlID0gMSwgYWxwaGEgPSAwLjUpICsKICBzY2FsZV9zaGFwZShzb2xpZCA9IEZBTFNFKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3VyID0gImJsdWUiKSArCiAgIyB4bGFiKCJUaW1lIGF0IFN0b3AgKHNlYykiKSArIAogICMgeWxhYigiTGF0ZW5lc3MgKHNlYykiKSArCiAgYW5ub3RhdGUobGFiZWwgPSBsbV9lcW4oZGYgPSBBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wLAogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wJERlbHRhX1RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IEFsbERheXNfTmV3T3JkZXJfTm9FeHRyZW1lc18xMFBjdFNhbXAkRHdlbGxfVGltZTIKICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgeCA9IDUwLAogICAgICAgICAgIHkgPSAtNDc1LAogICAgICAgICAgIGdlb20gPSAidGV4dCIsCiAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgY29sb3VyID0gImJsdWUiLAogICAgICAgICAgIHBhcnNlID0gVFJVRQogICAgICAgICAgKSArCiAgbGFicyh0aXRsZSA9ICJMYXRlbmVzcyB2cyBUaW1lIGF0IFN0b3AiLAogICAgICAgc3VidGl0bGUgPSAiKDIlIG9mIG91dGxpZXJzIHJlbW92ZWQpIiwKICAgICAgIHggPSAiVGltZSBhdCBTdG9wIChzZWMpIiwKICAgICAgIHkgPSAiTGF0ZW5lc3MgKHNlYykiCiAgICAgICkKICAjIGdndGl0bGUoZXhwcmVzc2lvbihhdG9wKCJMYXRlbmVzcyB2cyBUaW1lIGF0IFN0b3AiCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAsYXRvcChpdGFsaWMoIigyJSBvZiBvdXRsaWVycyByZW1vdmVkKSIpLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiIKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICMgICAgICAgICAgICAgICAgICAgICAgICApCiAgIyAgICAgICAgICAgICAgICAgICApCiAgIyAgICAgICAgKQojICsKIyAgIGdlb21faml0dGVyKCkKCkR3ZWxsVERlbHRhVF9TY2F0dGVyX05vRXh0cmVtZXMKCmBgYAoKClF1aWNrIGludmVzdGlnYXRpb24gb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIER3ZWxsX1RpbWUyICh0aGUgdGltZSBhIGJ1cyBpcyBhdCBhIHN0b3ApIGFuZCBEZWx0YV9UaW1lIChob3cgZWFybHkvbGF0ZSB0aGUgYnVzIGlzKS4KClBsb3R0aW5nIHRoZSBkYXRhIGZyb20gYm90aCBkYXRhc2V0cyB0b2dldGhlci4KYGBge3J9CgpDb21iaW5lZERhdGEgPC0gcmJpbmQoQWxsRGF5c19OZXdPcmRlcl8xMFBjdFNhbXAsCiAgICAgICAgICAgICAgICAgICAgICBBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wCiAgICAgICAgICAgICAgICAgICAgICkKCkNvbWJpbmVkRGF0YSREYXRhU2V0IDwtIGZhY3RvcihDb21iaW5lZERhdGEkRGF0YVNldCkKCnN0cihDb21iaW5lZERhdGEpCgoKRHdlbGxURGVsdGFUX1NjYXR0ZXJfQ29tYmluZWQgPC0gZ2dwbG90KENvbWJpbmVkRGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gRHdlbGxfVGltZTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IERlbHRhX1RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gRGF0YVNldAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBnZW9tX3BvaW50KHNoYXBlID0gMSwgYWxwaGEgPSAwLjUpICsKICBzY2FsZV9zaGFwZShzb2xpZCA9IEZBTFNFKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDUwMCksIHlsaW0gPSBjKC0xMDAwLCAyMDAwKQogICAgICAgICAgICAgICAgICkgKwogIGdlb21fc21vb3RoKGRhdGEgPSBmaWx0ZXIoQ29tYmluZWREYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRGF0YVNldCA9PSAiQWxsRGF0YSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLAogICAgICAgICAgICAgIGNvbG91ciA9ICJyZWQiCiAgICAgICAgICAgICApICsKICBnZW9tX3Ntb290aChkYXRhID0gZmlsdGVyKENvbWJpbmVkRGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIERhdGFTZXQgPT0gIk91dGxpZXJzUmVtb3ZlZCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLAogICAgICAgICAgICAgIGNvbG91ciA9ICJibHVlIgogICAgICAgICAgICAgKSArCiAgIyBmYWNldF93cmFwKCB+IERhdGFTZXQsIG5jb2wgPSAyKSArCiAgYW5ub3RhdGUobGFiZWwgPSBsbV9lcW4oZGYgPSBBbGxEYXlzX05ld09yZGVyXzEwUGN0U2FtcCwKICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQWxsRGF5c19OZXdPcmRlcl8xMFBjdFNhbXAkRGVsdGFfVGltZSwKICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gQWxsRGF5c19OZXdPcmRlcl8xMFBjdFNhbXAkRHdlbGxfVGltZTIKICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgeCA9IDMwMCwKICAgICAgICAgICB5ID0gLTYwMCwKICAgICAgICAgICBnZW9tID0gInRleHQiLAogICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgIGNvbG91ciA9ICJyZWQiLAogICAgICAgICAgIHBhcnNlID0gVFJVRQogICAgICAgICAgKSArCiAgYW5ub3RhdGUobGFiZWwgPSBsbV9lcW4oZGYgPSBBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wLAogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wJERlbHRhX1RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IEFsbERheXNfTmV3T3JkZXJfTm9FeHRyZW1lc18xMFBjdFNhbXAkRHdlbGxfVGltZTIKICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgeCA9IDMwMCwKICAgICAgICAgICB5ID0gLTgwMCwKICAgICAgICAgICBnZW9tID0gInRleHQiLAogICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgIGNvbG91ciA9ICJibHVlIiwKICAgICAgICAgICBwYXJzZSA9IFRSVUUKICAgICAgICAgICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh0aXRsZSA9ICJMYXRlbmVzcyB2cyBUaW1lIGF0IFN0b3AiLAogICAgICAgeCA9ICJUaW1lIGF0IFN0b3AgKHNlYykiLAogICAgICAgeSA9ICJMYXRlbmVzcyAoc2VjKSIKICAgICAgKQogICMgZ2d0aXRsZShleHByZXNzaW9uKGF0b3AoIkxhdGVuZXNzIHZzIFRpbWUgYXQgU3RvcCIKICAgICAgICAgICAgICAgICAgICAgICAgICAjICxhdG9wKGl0YWxpYygiMiUgb2Ygb3V0bGllcnMgcmVtb3ZlZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgIiIKICAgICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgKQogICAgICAgICAjICAgICAgICAgICAgICAgICApCiAgICAgICAgICMgICAgICAgICAgICApCiAgICAgICAgICMgKQojICsKIyAgIGdlb21faml0dGVyKCkKCkR3ZWxsVERlbHRhVF9TY2F0dGVyX0NvbWJpbmVkCgpgYGAKCgoKCgoKCgoKCgpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ21kK09wdGlvbitJKi4KCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ21kK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuCg==